KMOS Pipeline Reference Manual  1.3.7
kmo_sci_red.c
00001 /* 
00002  * This file is part of the KMOS Pipeline
00003  * Copyright (C) 2002,2003 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 /*-----------------------------------------------------------------------------
00025  *                                  Includes
00026  *----------------------------------------------------------------------------*/
00027 
00028 #include <string.h>
00029 #include <math.h>
00030 
00031 #include <cpl.h>
00032 
00033 #include "kmclipm_constants.h"
00034 #include "kmclipm_functions.h"
00035 
00036 #include "kmo_debug.h"
00037 #include "kmo_constants.h"
00038 #include "kmo_cpl_extensions.h"
00039 #include "kmo_priv_lcorr.h"
00040 #include "kmo_utils.h"
00041 #include "kmo_error.h"
00042 #include "kmo_dfs.h"
00043 #include "kmo_functions.h"
00044 #include "kmo_priv_arithmetic.h"
00045 #include "kmo_priv_combine.h"
00046 #include "kmo_priv_functions.h"
00047 #include "kmo_priv_reconstruct.h"
00048 #include "kmo_priv_sky_tweak.h"
00049 
00050 /*-----------------------------------------------------------------------------
00051  *                          Functions prototypes
00052  *----------------------------------------------------------------------------*/
00053 
00054 static int kmo_sci_red_create(cpl_plugin *);
00055 static int kmo_sci_red_exec(cpl_plugin *);
00056 static int kmo_sci_red_destroy(cpl_plugin *);
00057 static int kmo_sci_red(cpl_parameterlist *, cpl_frameset *);
00058 
00059 /*-----------------------------------------------------------------------------
00060  *                          Static variables
00061  *----------------------------------------------------------------------------*/
00062 
00063 static char kmo_sci_red_description[] =
00064 "Ideally at least two data frames have to be provided since we need for each\n"
00065 "IFU pointing to an object as well a sky frame for the same IFU.\n"
00066 "If an OH spectrum is given in the SOF file the lambda axis will be corrected\n"
00067 "using the OH lines as reference.\n"
00068 "Every IFU containing an object will be reconstructed and divided by telluric\n"
00069 "and illumination correction. By default these intermediate cubes are saved\n"
00070 "to disk. Frames just containing skies won’t produce an output here, so the\n"
00071 "number of output frames can be smaller than the number of input frames.\n"
00072 "Then the reconstructed objects with the same object name are combined. These\n"
00073 "outputs are also saved to disk, the number of created files depends on the\n"
00074 "number of reconstructed objects of different name. If the user just wants to\n"
00075 "combine a certain object, the parameters --name or --ifus can be used.\n"
00076 "For exposures taken with the templates KMOS_spec_obs_mapping8 and\n"
00077 "KMOS_spec_obs_mapping24 the recipe behaves a bit different: All active IFUs\n"
00078 "will be combined, regardless of the object names.\n"
00079 "\n"
00080 "BASIC PARAMETERS:\n"
00081 "-----------------\n"
00082 "--imethod\n"
00083 "The interpolation method used for reconstruction.\n"
00084 "\n"
00085 "--smethod\n"
00086 "The interpolation method used for shifting.\n"
00087 "\n"
00088 "--name\n"
00089 "--ifus\n"
00090 "Since an object can be present only once per exposure and since it can be\n"
00091 "located in different IFUs for the existing exposures, there are two modes\n"
00092 "to identify the objects:\n"
00093 "   * Combine by object names (default)\n"
00094 "   In this case the object name must be provided via the --name parameter.\n"
00095 "   The object name will be searched for in all primary headers of all\n"
00096 "   provided frames in the keyword ESO OCS ARMx NAME.\n"
00097 "\n"
00098 "   * Combine by index (advanced)\n"
00099 "   In this case the --ifus parameter must be provided. The parameter must\n"
00100 "   have the same number of entries as frames are provided, e.g.  \"3;1;24\"\n"
00101 "   for 3 exposures. The index doesn't reference the extension in the frame\n"
00102 "   but the real index of the IFU as defined in the EXTNAME keyword.\n"
00103 "   (e.g. 'IFU.3.DATA')\n"
00104 "\n"
00105 "ADVANCED PARAMETERS\n"
00106 "-------------------\n"
00107 "--flux\n"
00108 "Specify if flux conservation should be applied.\n"
00109 "\n"
00110 "--background\n"
00111 "Specify if background removal should be applied.\n"
00112 "\n"
00113 "--suppress_extension\n"
00114 "If set to TRUE, the arbitrary filename extensions are supressed. If multiple\n"
00115 "products with the same category are produced, they will be numered\n"
00116 "consecutively starting from 0.\n"
00117 "\n"
00118 "--sky_tweak\n"
00119 "If set to TRUE sky substraction is not done by subtracting the corresponding\n"
00120 "detector images but subtracting a modified sky cube from the object cube.\n"
00121 "It is not allowed that \"--sky_tweak\" and \"--no_subtract\" both are TRUE.\n"
00122 "\n"
00123 "--tbsub\n"
00124 "If set to TRUE subtract the thermal background from the cube resulting from\n"
00125 "sky tweaking.\n"
00126 "Default value is TRUE.\n"
00127 "\n"
00128 "--obj_sky_table\n"
00129 "The automatic obj-sky-associations can be modified by indicating a file with\n"
00130 "the desired associations. Therefore the file written to disk by default\n"
00131 "(without setting this option) can be edited manually. The formatting must\n"
00132 "absolutely be retained, just the type codes ('O' and'S') and the associated\n"
00133 "frame indices should be altered\n"
00134 "\n"
00135 "  Advanced reconstruction parameters\n"
00136 "  ----------------------------------\n"
00137 "--neighborhoodRange\n"
00138 "Defines the range to search for neighbors during reconstruction\n"
00139 "\n"
00140 "--b_samples\n"
00141 "The number of samples in spectral direction for the reconstructed cube.\n"
00142 "Ideally this number should be greater than 2048, the detector size.\n"
00143 "\n"
00144 "--b_start\n"
00145 "--b_end\n"
00146 "Used to define manually the start and end wavelength for the reconstructed\n"
00147 "cube. By default the internally defined values are used.\n"
00148 "\n"
00149 "--fast_mode\n"
00150 "If set to TRUE, the reconstructed cubes will be collapsed (using median) and\n"
00151 "only then be shifted and combined.\n"
00152 "\n"
00153 "--pix_scale\n"
00154 "Change the pixel scale [arcsec]. Default of 0.2\" results into cubes of\n"
00155 "14x14pix, a scale of 0.1\" results into cubes of 28x28pix, etc.\n"
00156 "\n"
00157 "--no_subtract\n"
00158 "If set to TRUE, the found objects and references won't be sky subtracted. \n"
00159 "Additionally all IFUs will be reconstructed, even the ones containing skies.\n"
00160 "This option sets the parameter no_combine to TRUE automatically.\n"
00161 "\n"
00162 "--xcal_interpolation\n"
00163 "If true interpolate the pixel position in the slitlet (xcal) using the two\n"
00164 "closest rotator angles in the calibration file. Otherwise take the values\n"
00165 "of the closest rotator angle\n"
00166 "\n"
00167 "--extrapolate\n"
00168 "By default no extrapolation is applied. This means that the intermediate\n"
00169 "reconstructed cubes will shrink at most one pixel, which is ok for templates\n"
00170 "like KMOS_spec_obs_nodtosky or KMOS_spec_obs_freedither. When the cubes will\n"
00171 "be arranged as a map, a grid is likely to occur between the IFUs. Therefore\n"
00172 "extrapolation during the shifting process can be switched on in order to get\n"
00173 "IFUs of original size. For frames taken with mapping templates,\n"
00174 "extrapolation is switched on automatically.\n"
00175 "\n"
00176 "--velocity_offset\n"
00177 "Specifies the velocity offset correction in km/s for lambda scale.\n"
00178 "Default is 0.0 km/s, i.e. no velocity correction.\n"
00179 "\n"
00180 "--save_interims\n"
00181 "If set to TRUE the interim object and sky cubes used for sky tweaking are\n"
00182 "saved to FITS file in the same format as SCI_RECONSTRUCTED\n"
00183  "Default is FALSE.\n"
00184  "\n"
00185 "  Advanced combining parameters\n"
00186 "  ----------------------------------\n"
00187 "--edge_nan\n"
00188 "Set borders of two sides of the cubes to NaN before combining them. This\n"
00189 "minimises unwanted border effects when dithering.\n"
00190 "\n"
00191 "--no_combine\n"
00192 "If set to TRUE, the reconstructed cubes will not be combined.\n"
00193 "\n"
00194 "--method\n"
00195 "There are following sources to get the shift parameters from:\n"
00196 "   * 'header' (default)\n"
00197 "   The shifts are calculated according to the WCS information stored in the\n"
00198 "   header of every IFU. The output frame will get larger, except the object\n"
00199 "   is at the exact same position for all exposures. The size of the\n"
00200 "   exposures can differ, but the orientation must be the same for all\n"
00201 "   exposures.\n"
00202 "\n"
00203 "   * 'none'\n"
00204 "   The cubes are directly recombined, not shifting at all. The ouput frame\n"
00205 "   will have the same dimensions as the input cubes.\n"
00206 "   If the size differs a warning will be emitted and the cubes will be\n"
00207 "   aligned to the lower left corner. If the orientation differs a warning\n"
00208 "   will be emitted, but the cubes are combined anyway.\n"
00209 "\n"
00210 "   * 'center'\n"
00211 "   The shifts are calculated using a centering algorithm. The cube will be\n"
00212 "   collapsed and a 2D profile will be fitted to it to identify the centre.\n"
00213 "   With the parameter --fmethod the function to fit can be provided. The\n"
00214 "   size of the exposures can differ, but the orientation must be the same\n"
00215 "   for all exposures.\n"
00216 "\n"
00217 "   * 'user'\n"
00218 "   Read the shifts from a user specified file. The path of the file must be\n"
00219 "   provided using the --filename parameter. For every exposure (except the\n"
00220 "   first one) two shift values are expected per line, they have to be\n"
00221 "   separated with simple spaces. The values indicate pixel shifts and are\n"
00222 "   referenced to the first frame. The 1st value is the shift in x-direction\n"
00223 "   to the left, the 2nd the shift in y-direction upwards. The size of the\n"
00224 "   exposures can differ, but the orientation must be the same for all\n"
00225 "   exposures.\n"
00226 "\n"
00227 "--fmethod\n"
00228 "see --method='center'\n"
00229 "The type of function that should be fitted spatially to the collapsed image.\n"
00230 "This fit is used to create a mask to extract the spectrum of the object.\n"
00231 "Valid values are 'gauss' and 'moffat'.\n"
00232 "\n"
00233 "--filename\n"
00234 "see --method='user'\n"
00235 "\n"
00236 "--cmethod\n"
00237 "Following methods of frame combination are available:\n"
00238 "   * 'ksigma' (Default)\n"
00239 "   An iterative sigma clipping. For each position all pixels in the spectrum\n"
00240 "   are examined. If they deviate significantly, they will be rejected\n"
00241 "   according to the conditions:\n"
00242 "       val > mean + stdev * cpos_rej\n"
00243 "   and\n"
00244 "       val < mean - stdev * cneg_rej\n"
00245 "   where --cpos_rej, --cneg_rej and --citer are the corresponding\n"
00246 "   configuration parameters. In the first iteration median and percentile\n"
00247 "   level are used.\n"
00248 "\n"
00249 "   * 'median'\n"
00250 "   At each pixel position the median is calculated.\n"
00251 "\n"
00252 "   * 'average'\n"
00253 "   At each pixel position the average is calculated.\n"
00254 "\n"
00255 "   * 'sum'\n"
00256 "   At each pixel position the sum is calculated.\n"
00257 "\n"
00258 "   * 'min_max'\n"
00259 "   The specified number of minimum and maximum pixel values will be\n"
00260 "   rejected.\n"
00261 "   --cmax and --cmin apply to this method.\n"
00262 "\n"
00263 "--cpos_rej\n"
00264 "--cneg_rej\n"
00265 "--citer\n"
00266 "see --cmethod='ksigma'\n"
00267 "\n"
00268 "--cmax\n"
00269 "--cmin\n"
00270 "see --cmethod='min_max'\n"
00271 "\n"
00272 "--------------------------------------------------------------------------\n"
00273 "  Input files:\n"
00274 "\n"
00275 "   DO                KMOS                                                 \n"
00276 "   category          Type   Explanation                   Required #Frames\n"
00277 "   --------          -----  -----------                   -------- -------\n"
00278 "   SCIENCE           RAW    The science frames                Y      >=1  \n"
00279 "   XCAL              F2D    x calibration frame               Y       1   \n"
00280 "   YCAL              F2D    y calibration frame               Y       1   \n"
00281 "   LCAL              F2D    Wavelength calib. frame           Y       1   \n"
00282 "   WAVE_BAND         F2L    Table with start-/end-wavelengths Y       1   \n"
00283 "   MASTER_FLAT       F2D    Master flat                       Y      0,1  \n"
00284 "   ILLUM_CORR        F2I    Illumination correction           N      0,1  \n"
00285 "   TELLURIC          F1I    normalised telluric spectrum      N      0,1  \n"
00286 "   OH_SPEC           F1S    Vector holding OH lines           N      0,1  \n"
00287 "\n"
00288 "  Output files:\n"
00289 "\n"
00290 "   DO                KMOS\n"
00291 "   category          Type   Explanation\n"
00292 "   --------              -----  -----------\n"
00293 "   SCI_COMBINED      F3I    Combined cubes with noise\n"
00294 "   SCI_RECONSTRUCTED F3I    Reconstructed cube with noise\n"
00295 "   EXP_MASK          F3I    Exposure time mask (not for mapping-templates!)\n"
00296 "   SCI_INTERIM_OBJECT F3I    (optional) Intermediate reconstructed object \n"
00297 "                            cubes used for sky tweaking, no noise \n"
00298 "                            (set --sky_tweak and --save_interims)\n"
00299 "   SCI_INTERIM_SKY   F3I    (optional) Intermediate reconstructed sky \n"
00300 "                            cubes used for sky tweaking, no noise\n"
00301 "                            (set --sky_tweak and --save_interims)\n"
00302 "--------------------------------------------------------------------------\n"
00303 "\n";
00304 
00305 /*-----------------------------------------------------------------------------
00306  *                              Functions code
00307  *----------------------------------------------------------------------------*/
00308 
00309 /*----------------------------------------------------------------------------*/
00314 /*----------------------------------------------------------------------------*/
00315 
00318 /*----------------------------------------------------------------------------*/
00327 /*----------------------------------------------------------------------------*/
00328 int cpl_plugin_get_info(cpl_pluginlist *list)
00329 {
00330     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00331     cpl_plugin *plugin = &recipe->interface;
00332 
00333     cpl_plugin_init(plugin,
00334             CPL_PLUGIN_API,
00335             KMOS_BINARY_VERSION,
00336             CPL_PLUGIN_TYPE_RECIPE,
00337             "kmo_sci_red",
00338             "Reconstruct obj/sky-pairs individually and combine "
00339             "them afterwards",
00340             kmo_sci_red_description,
00341             "Alex Agudo Berbel",
00342             "usd-help@eso.org",
00343             kmos_get_license(),
00344             kmo_sci_red_create,
00345             kmo_sci_red_exec,
00346             kmo_sci_red_destroy);
00347 
00348     cpl_pluginlist_append(list, plugin);
00349 
00350     return 0;
00351 }
00352 
00353 /*----------------------------------------------------------------------------*/
00361 /*----------------------------------------------------------------------------*/
00362 static int kmo_sci_red_create(cpl_plugin *plugin)
00363 {
00364     cpl_recipe *recipe;
00365     cpl_parameter *p;
00366 
00367     /* Check that the plugin is part of a valid recipe */
00368     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00369         recipe = (cpl_recipe *)plugin;
00370     else
00371         return -1;
00372 
00373     /* Create the parameters list in the cpl_recipe object */
00374     recipe->parameters = cpl_parameterlist_new();
00375 
00376     /* --imethod (interpolation method) */
00377     p = cpl_parameter_new_value("kmos.kmo_sci_red.imethod", CPL_TYPE_STRING,
00378             "Method to use for interpolation during reconstruction. "
00379             "[\"NN\" (nearest neighbour), "
00380             "\"lwNN\" (linear weighted nearest neighbor), "
00381             "\"swNN\" (square weighted nearest neighbor), "
00382             "\"MS\" (Modified Shepard's method)"
00383             "\"CS\" (Cubic spline)]",
00384             "kmos.kmo_sci_red", "CS");
00385     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00386     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00387     cpl_parameterlist_append(recipe->parameters, p);
00388 
00389     /* --smethod  (shift interpolation method) */
00390     p = cpl_parameter_new_value("kmos.kmo_sci_red.smethod", CPL_TYPE_STRING,
00391             "Method to use for interpolation during shifting. "
00392             "[\"NN\" (nearest neighbour), "
00393             "\"CS\" (Cubic spline)]",
00394             "kmos.kmo_sci_red", "CS");
00395     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "smethod");
00396     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00397     cpl_parameterlist_append(recipe->parameters, p);
00398 
00399     /* --method  (shift method) */
00400     p = cpl_parameter_new_value("kmos.kmo_sci_red.method", CPL_TYPE_STRING,
00401             "The shifting method:   "
00402             "'none': no shifting, combined directly, "
00403             "'header': shift according to WCS (default), "
00404             "'center': centering algorithm, "
00405             "'user': read shifts from file",
00406             "kmos.kmo_sci_red", "header");
00407     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
00408     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00409     cpl_parameterlist_append(recipe->parameters, p);
00410 
00411     /* --fmethod */
00412     p = cpl_parameter_new_value("kmos.kmo_sci_red.fmethod", CPL_TYPE_STRING,
00413             "The fitting method (applies only when method='center'):   "
00414             "'gauss': fit a gauss function to collapsed image (default), "
00415             "'moffat': fit a moffat function to collapsed image",
00416             "kmos.kmo_sci_red", "gauss");
00417     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00418     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00419     cpl_parameterlist_append(recipe->parameters, p);
00420 
00421     /* --name */
00422     p = cpl_parameter_new_value("kmos.kmo_sci_red.name", CPL_TYPE_STRING,
00423             "Name of the object to combine.", "kmos.kmo_sci_red", "");
00424     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00425     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00426     cpl_parameterlist_append(recipe->parameters, p);
00427 
00428     /* --ifus */
00429     p = cpl_parameter_new_value("kmos.kmo_sci_red.ifus", CPL_TYPE_STRING,
00430             "The indices of the IFUs to combine. \"ifu1;ifu2;...\"", 
00431             "kmos.kmo_sci_red", "");
00432     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00433     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00434     cpl_parameterlist_append(recipe->parameters, p);
00435 
00436     /* --pix_scale */
00437     p = cpl_parameter_new_value("kmos.kmo_sci_red.pix_scale", CPL_TYPE_DOUBLE,
00438             "Change the pixel scale [arcsec]. "
00439             "Default of 0.2\" results into cubes of 14x14pix, "
00440             "a scale of 0.1\" results into cubes of 28x28pix, etc.",
00441             "kmos.kmo_sci_red", KMOS_PIX_RESOLUTION);
00442     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
00443     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00444     cpl_parameterlist_append(recipe->parameters, p);
00445 
00446     /* --suppress_extension */
00447     p = cpl_parameter_new_value("kmos.kmo_sci_red.suppress_extension",
00448             CPL_TYPE_BOOL,
00449             "Suppress arbitrary filename extension."
00450             "(TRUE (apply) or FALSE (don't apply)",
00451             "kmos.kmo_sci_red", FALSE);
00452     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
00453     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00454     cpl_parameterlist_append(recipe->parameters, p);
00455 
00456     /* --neighborhoodRange */
00457     p = cpl_parameter_new_value("kmos.kmo_sci_red.neighborhoodRange",
00458             CPL_TYPE_DOUBLE, 
00459             "Defines the range to search for neighbors in pixels",
00460             "kmos.kmo_sci_red", 1.001);
00461     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00462     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00463     cpl_parameterlist_append(recipe->parameters, p);
00464 
00465     /* --filename */
00466     p = cpl_parameter_new_value("kmos.kmo_sci_red.filename", CPL_TYPE_STRING,
00467             "The path to the file with the shift vectors."
00468             "(Applies only to method='user')",
00469             "kmos.kmo_sci_red", "");
00470     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00471     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00472     cpl_parameterlist_append(recipe->parameters, p);
00473 
00474     /* --flux */
00475     p = cpl_parameter_new_value("kmos.kmo_sci_red.flux", CPL_TYPE_BOOL,
00476             "TRUE: Apply flux conservation. FALSE: otherwise", 
00477             "kmos.kmo_sci_red", FALSE);
00478     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00479     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00480     cpl_parameterlist_append(recipe->parameters, p);
00481 
00482     /* --background */
00483     p = cpl_parameter_new_value("kmos.kmo_sci_red.background", CPL_TYPE_BOOL, 
00484             "TRUE: Apply background removal. FALSE: otherwise",
00485             "kmos.kmo_sci_red", FALSE);
00486     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "background");
00487     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00488     cpl_parameterlist_append(recipe->parameters, p);
00489 
00490     /* --fast_mode */
00491     p = cpl_parameter_new_value("kmos.kmo_sci_red.fast_mode", CPL_TYPE_BOOL,
00492             "FALSE: cubes are shifted and combined,"
00493             "TRUE: cubes are collapsed and then shifted and combined",
00494             "kmos.kmo_sci_red", FALSE);
00495     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fast_mode");
00496     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00497     cpl_parameterlist_append(recipe->parameters, p);
00498 
00499     /* --extrapolate */
00500     p = cpl_parameter_new_value("kmos.kmo_sci_red.extrapolate", CPL_TYPE_BOOL,
00501             "Applies only to 'smethod=CS' when doing sub-pixel shifts: "
00502             "FALSE: shifted IFU will be filled with NaN's at the borders,"
00503             "TRUE: shifted IFU will be extrapolated at the borders",
00504             "kmos.kmo_sci_red", FALSE);
00505     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate");
00506     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00507     cpl_parameterlist_append(recipe->parameters, p);
00508 
00509     /* --xcal_interpolation */
00510     p = cpl_parameter_new_value("kmos.kmo_sci_red.xcal_interpolation",
00511             CPL_TYPE_BOOL,
00512             "TRUE: Interpolate xcal between rotator angles. FALSE: otherwise",
00513             "kmos.kmo_sci_red", TRUE);
00514     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcal_interpolation");
00515     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00516     cpl_parameterlist_append(recipe->parameters, p);
00517 
00518     /* --edge_nan */
00519     p = cpl_parameter_new_value("kmos.kmo_sci_red.edge_nan", CPL_TYPE_BOOL,
00520             "Set borders of cubes to NaN before combining them."
00521             "(TRUE (apply) or FALSE (don't apply)",
00522             "kmos.kmo_sci_red", FALSE);
00523     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edge_nan");
00524     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00525     cpl_parameterlist_append(recipe->parameters, p);
00526 
00527     /* --no_combine */
00528     p = cpl_parameter_new_value("kmos.kmo_sci_red.no_combine", CPL_TYPE_BOOL,
00529             "Don't combine cubes after reconstruction."
00530             "(TRUE (apply) or FALSE (don't apply)",
00531             "kmos.kmo_sci_red", FALSE);
00532     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_combine");
00533     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00534     cpl_parameterlist_append(recipe->parameters, p);
00535 
00536     /* --no_subtract */
00537     p = cpl_parameter_new_value("kmos.kmo_sci_red.no_subtract", CPL_TYPE_BOOL,
00538             "Don't sky subtract object and references."
00539             "(TRUE (apply) or FALSE (don't apply)",
00540             "kmos.kmo_sci_red", FALSE);
00541     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_subtract");
00542     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00543     cpl_parameterlist_append(recipe->parameters, p);
00544 
00545     /* --sky_tweak */
00546     p = cpl_parameter_new_value("kmos.kmo_sci_red.sky_tweak", CPL_TYPE_BOOL,
00547             "Use modified sky cube for sky subtraction."
00548             "(TRUE (apply) or FALSE (don't apply)",
00549             "kmos.kmo_sci_red", FALSE);
00550     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_tweak");
00551     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00552     cpl_parameterlist_append(recipe->parameters, p);
00553 
00554     /* --tbsub */
00555     p = cpl_parameter_new_value("kmos.kmo_sci_red.tbsub", CPL_TYPE_BOOL,
00556             "Subtract thermal background from input cube."
00557             "(TRUE (apply) or FALSE (don't apply)",
00558             "kmos.kmo_sci_red", TRUE);
00559     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "tbsub");
00560     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00561     cpl_parameterlist_append(recipe->parameters, p);
00562 
00563     // add parameters for band-definition
00564     kmos_band_pars_create(recipe->parameters, "kmos.kmo_sci_red");
00565 
00566     /* --obj_sky_table */
00567     p = cpl_parameter_new_value("kmos.kmo_sci_red.obj_sky_table",
00568             CPL_TYPE_STRING,
00569             "The path to the file with the modified obj/sky associations.",
00570             "kmos.kmo_sci_red", "");
00571     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "obj_sky_table");
00572     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00573     cpl_parameterlist_append(recipe->parameters, p);
00574 
00575     /* --velocity_offset */
00576     p = cpl_parameter_new_value("kmos.kmo_sci_red.velocity_offset",
00577             CPL_TYPE_DOUBLE,
00578             "Specify velocity offset correction in km/s for lambda scale",
00579             "kmos.kmo_sci_red", 0.0);
00580     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "velocity_offset");
00581     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00582     cpl_parameterlist_append(recipe->parameters, p);
00583 
00584     /* --save_interims */
00585     p = cpl_parameter_new_value("kmos.kmo_sci_red.save_interims", CPL_TYPE_BOOL,
00586             "Save interim object and sky cubes. "
00587             "Can only be used together with --sky_tweak",
00588             "kmos.kmo_sci_red", FALSE);
00589     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_interims");
00590     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00591     cpl_parameterlist_append(recipe->parameters, p);
00592 
00593     return kmos_combine_pars_create(recipe->parameters, "kmos.kmo_sci_red",
00594             DEF_REJ_METHOD, FALSE);
00595 }
00596 
00597 /*----------------------------------------------------------------------------*/
00603 /*----------------------------------------------------------------------------*/
00604 static int kmo_sci_red_exec(cpl_plugin *plugin)
00605 {
00606     cpl_recipe  *recipe;
00607 
00608     /* Get the recipe out of the plugin */
00609     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00610         recipe = (cpl_recipe *)plugin;
00611     else return -1 ;
00612 
00613     return kmo_sci_red(recipe->parameters, recipe->frames);
00614 }
00615 
00616 /*----------------------------------------------------------------------------*/
00622 /*----------------------------------------------------------------------------*/
00623 static int kmo_sci_red_destroy(cpl_plugin *plugin)
00624 {
00625     cpl_recipe *recipe;
00626 
00627     /* Get the recipe out of the plugin */
00628     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00629         recipe = (cpl_recipe *)plugin;
00630     else return -1 ;
00631 
00632     cpl_parameterlist_delete(recipe->parameters);
00633     return 0 ;
00634 }
00635 
00636 /*----------------------------------------------------------------------------*/
00649 /*----------------------------------------------------------------------------*/
00650 static int kmo_sci_red(cpl_parameterlist *parlist, cpl_frameset *frameset)
00651 {
00652     int                     ret_val                     = 0,
00653                             nr_science_frames           = 0,
00654                             nr_reconstructed_frames     = 0,
00655                             has_illum_corr              = 0,
00656                             has_master_flat             = 0,
00657                             has_telluric                = 0,
00658                             has_oh_spec                 = 0,
00659                             telluric_ok                 = 0,
00660                             *bounds                     = NULL,
00661                             det_nr                      = 0,
00662                             actual_msg_level            = 0,
00663                             print_once                  = FALSE,
00664                             cube_counter_data           = 0,
00665                             cube_counter_noise          = 0,
00666                             citer                       = 0,
00667                             cmin                        = 0,
00668                             cmax                        = 0,
00669                             extrapolate                 = 0,
00670                             flux                        = FALSE,
00671                             background                  = FALSE,
00672                             index                       = 0,
00673                             nr_data_alloc               = 0,
00674                             tmp_int                     = 0,
00675                             fast_mode                   = FALSE,
00676                             edge_nan                    = FALSE,
00677                             no_combine                  = FALSE,
00678                             no_subtract                 = FALSE,
00679                             do_sky_subtraction          = FALSE,
00680                             sky_tweak                   = FALSE,
00681                             tbsub                       = TRUE,
00682                             save_interims               = FALSE,
00683                             xcal_interpolation          = FALSE,
00684                             suppress_extension          = FALSE,
00685                             suppress_index              = 0,
00686                             i                           = 0,
00687                             sf                          = 0,
00688                             jj                          = 0,
00689                             ifu_nr                      = 0,
00690                             sky_ifu_nr                  = 0;
00691     double                  neighborhoodRange           = 1.001,
00692                             cpos_rej                    = 0.0,
00693                             cneg_rej                    = 0.0,
00694                             pix_scale                   = 0.0,
00695                             velo_offset                 = 0.0,
00696                             velo_corr                   = 0.0;
00697     double                  *velo_corr_ptr              = NULL;
00698     char                    *suffix                     = NULL,
00699                             *keyword                    = NULL,
00700                             *extname                    = NULL,
00701                             *fn_suffix                  = NULL,
00702                             *mapping_mode               = NULL,
00703                             **split                     = NULL,
00704                             content[256];
00705     const char              *imethod                    = NULL,
00706                             *smethod                    = NULL,
00707                             *ifus_txt                   = NULL,
00708                             *name                       = NULL,
00709                             *filter_id                  = NULL,
00710                             *tmp_str                    = NULL,
00711                             *filename                   = NULL,
00712                             *fn_obj_sky_table           = NULL,
00713                             *fn_out                     = NULL,
00714                             *fn_out_mask                = NULL,
00715                             *fn_obj                     = NULL,
00716                             *fn_sky                     = NULL,
00717                             *fn_reconstr                = NULL,
00718                             *fn_interim_object          = NULL,
00719                             *fn_interim_sky             = NULL,
00720                             *comb_method                = NULL,
00721                             *cmethod                    = NULL,
00722                             *fmethod                    = NULL;
00723     cpl_array               **unused_ifus_before        = NULL,
00724                             **unused_ifus_after         = NULL;
00725     cpl_frame               *xcal_frame                 = NULL,
00726                             *ycal_frame                 = NULL,
00727                             *lcal_frame                 = NULL,
00728                             *flat_frame                 = NULL,
00729                             *illum_frame                = NULL,
00730                             *telluric_frame             = NULL,
00731                             *tmp_frame                  = NULL;
00732     cpl_propertylist        *tmp_header                 = NULL,
00733                             *main_header                = NULL,
00734                             *main_sky_header            = NULL,
00735                             **header_data               = NULL,
00736                             **header_noise              = NULL,
00737                             **header_sky                = NULL;
00738     cpl_vector              *ifus                       = NULL;
00739     kmclipm_vector          *telluric_data              = NULL,
00740                             *telluric_noise             = NULL;
00741     cpl_image               **lcal                      = NULL,
00742                             *illum_data                 = NULL,
00743                             *illum_noise                = NULL,
00744                             *tmpImg                     = NULL,
00745                             *exp_mask                   = NULL;
00746     cpl_imagelist           **cube_data                 = NULL,
00747                             **cube_noise                = NULL,
00748                             **cube_interim_object       = NULL,
00749                             **cube_interim_sky          = NULL,
00750                             *sky_data                   = NULL,
00751                             *sky_noise                  = NULL,
00752                             *combined_data              = NULL,
00753                             *combined_noise             = NULL,
00754                             *tmpCube                    = NULL;
00755     cpl_table               *band_table                 = NULL;
00756     cpl_frame               *sky_frame                  = NULL,
00757                             *sky_as_object_frame        = NULL,
00758                             *ref_spectrum_frame         = NULL;
00759     cpl_polynomial          *oh_lcorr_coeffs            = NULL;
00760     main_fits_desc          desc1,
00761                             desc2,
00762                             desc_telluric;
00763     gridDefinition          gd;
00764     armNameStruct           *arm_name_struct            = NULL;
00765     enum extrapolationType  extrapol_enum               = 0;
00766     enum kmo_frame_type     ft                          = 0;
00767 
00768     KMO_TRY
00769     {
00770         kmo_init_fits_desc(&desc1);
00771         kmo_init_fits_desc(&desc2);
00772         kmo_init_fits_desc(&desc_telluric);
00773 
00774         /* Check frameset */
00775         KMO_TRY_ASSURE((parlist != NULL) && (frameset != NULL),
00776                 CPL_ERROR_NULL_INPUT, "Not all input data is provided!");
00777 
00778         nr_science_frames = cpl_frameset_count_tags(frameset, SCIENCE);
00779         KMO_TRY_ASSURE(nr_science_frames >= 1, CPL_ERROR_ILLEGAL_INPUT,
00780                 "At least one SCIENCE frame is required!");
00781         if (nr_science_frames == 1) {
00782             cpl_msg_warning(__func__, 
00783                     "2 SCIENCE frames are needed for sky subtraction");
00784             cpl_msg_warning(__func__, 
00785                     "All IFUs are reconstructed (object, reference and sky");
00786         }
00787 
00788         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00789                        CPL_ERROR_FILE_NOT_FOUND,
00790                        "Exactly one XCAL frame is required");
00791 
00792         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00793                        CPL_ERROR_FILE_NOT_FOUND,
00794                        "Exactly one YCAL frame is required");
00795 
00796         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00797                        CPL_ERROR_FILE_NOT_FOUND,
00798                        "Exactly one LCAL frame is required");
00799 
00800         has_master_flat = cpl_frameset_count_tags(frameset, MASTER_FLAT);
00801         KMO_TRY_ASSURE((has_master_flat == 0) || (has_master_flat == 1),
00802                        CPL_ERROR_FILE_NOT_FOUND,
00803                        "At most one MASTER_FLAT frame can be provided");
00804 
00805         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00806                        CPL_ERROR_FILE_NOT_FOUND,
00807                        "Exactly one WAVE_BAND frame is required");
00808 
00809         has_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
00810         KMO_TRY_ASSURE((has_illum_corr == 0) || (has_illum_corr == 1),
00811                        CPL_ERROR_FILE_NOT_FOUND,
00812                        "At most one ILLUM_CORR frame can be provided");
00813 
00814         has_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
00815         KMO_TRY_ASSURE((has_telluric == 0) || (has_telluric == 1),
00816                        CPL_ERROR_FILE_NOT_FOUND,
00817                        "At most one TELLURIC frame can be provided");
00818 
00819         has_oh_spec = cpl_frameset_count_tags(frameset, OH_SPEC) ;
00820         KMO_TRY_ASSURE(has_oh_spec == 0 || has_oh_spec == 1,
00821                        CPL_ERROR_ILLEGAL_INPUT,
00822                        "Only a single reference spectrum can be provided!");
00823 
00824         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_sci_red") == 1,
00825                        CPL_ERROR_ILLEGAL_INPUT,
00826                        "Cannot identify RAW and CALIB frames!");
00827 
00828         /* Get parameters */
00829         cpl_msg_info("", "--- Parameter setup for kmo_sci_red ------");
00830         flux = kmo_dfs_get_parameter_bool(parlist, "kmos.kmo_sci_red.flux");
00831         KMO_TRY_ASSURE((flux == 0) || (flux == 1), CPL_ERROR_ILLEGAL_INPUT,
00832                 "flux must be either FALSE or TRUE! %d", flux);
00833         KMO_TRY_EXIT_IF_ERROR(
00834             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.flux"));
00835         background = kmo_dfs_get_parameter_bool(parlist, 
00836                 "kmos.kmo_sci_red.background");
00837         KMO_TRY_ASSURE((background == 0) || (background == 1),
00838                 CPL_ERROR_ILLEGAL_INPUT,
00839                 "background must be either FALSE or TRUE! %d", background);
00840         KMO_TRY_EXIT_IF_ERROR(
00841             kmo_dfs_print_parameter_help(parlist, 
00842                 "kmos.kmo_sci_red.background"));
00843         KMO_TRY_EXIT_IF_NULL(
00844             imethod = kmo_dfs_get_parameter_string(parlist, 
00845                 "kmos.kmo_sci_red.imethod"));
00846         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00847                 (strcmp(imethod, "lwNN") == 0) ||
00848                 (strcmp(imethod, "swNN") == 0) ||
00849                 (strcmp(imethod, "MS") == 0) ||
00850                 (strcmp(imethod, "CS") == 0),
00851                 CPL_ERROR_ILLEGAL_INPUT,
00852         "imethod must be either \"NN\", \"lwNN\", \"swNN\", \"MS\" or \"CS\"!");
00853         KMO_TRY_EXIT_IF_ERROR(
00854             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.imethod"));
00855         KMO_TRY_EXIT_IF_NULL(
00856             smethod = kmo_dfs_get_parameter_string(parlist, 
00857                 "kmos.kmo_sci_red.smethod"));
00858         KMO_TRY_ASSURE((strcmp(smethod, "NN") == 0) ||
00859                 (strcmp(smethod, "CS") == 0), CPL_ERROR_ILLEGAL_INPUT,
00860                 "smethod must be either \"NN\" or \"CS\"!");
00861         KMO_TRY_EXIT_IF_ERROR(
00862             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.smethod"));
00863         neighborhoodRange = kmo_dfs_get_parameter_double(parlist, 
00864                 "kmos.kmo_sci_red.neighborhoodRange");
00865         KMO_TRY_CHECK_ERROR_STATE();
00866         KMO_TRY_ASSURE(neighborhoodRange > 0.0, CPL_ERROR_ILLEGAL_INPUT,
00867                 "neighborhoodRange must be greater than 0.0");
00868         KMO_TRY_EXIT_IF_ERROR(
00869             kmo_dfs_print_parameter_help(parlist, 
00870                 "kmos.kmo_sci_red.neighborhoodRange"));
00871         KMO_TRY_EXIT_IF_NULL(
00872             comb_method = kmo_dfs_get_parameter_string(parlist, 
00873                 "kmos.kmo_sci_red.method"));
00874         KMO_TRY_EXIT_IF_NULL(
00875             fmethod = kmo_dfs_get_parameter_string(parlist, 
00876                 "kmos.kmo_sci_red.fmethod"));
00877         KMO_TRY_ASSURE((strcmp(comb_method, "none") == 0) ||
00878                 (strcmp(comb_method, "header") == 0) ||
00879                 (strcmp(comb_method, "center") == 0) ||
00880                 (strcmp(comb_method, "user") == 0), CPL_ERROR_ILLEGAL_INPUT,
00881 "Following shift methods are available : 'none', 'header', 'center' or 'user'");
00882         if (strcmp(comb_method, "user") == 0) {
00883             filename = kmo_dfs_get_parameter_string(parlist, 
00884                     "kmos.kmo_sci_red.filename");
00885             KMO_TRY_CHECK_ERROR_STATE();
00886             KMO_TRY_ASSURE(strcmp(filename, "") != 0, CPL_ERROR_ILLEGAL_INPUT,
00887                     "path of file with shift information must be provided!");
00888             KMO_TRY_EXIT_IF_ERROR(
00889                 kmo_dfs_print_parameter_help(parlist, 
00890                     "kmos.kmo_sci_red.filename"));
00891         }
00892         KMO_TRY_EXIT_IF_ERROR(
00893             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.method"));
00894 
00895         ifus_txt=kmo_dfs_get_parameter_string(parlist, "kmos.kmo_sci_red.ifus");
00896         KMO_TRY_CHECK_ERROR_STATE();
00897         name = kmo_dfs_get_parameter_string(parlist, "kmos.kmo_sci_red.name");
00898         KMO_TRY_CHECK_ERROR_STATE();
00899         if (strcmp(ifus_txt, "") != 0) {
00900             KMO_TRY_ASSURE(strcmp(name, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
00901                     "name parameter must be NULL if IFU indices are provided!");
00902             KMO_TRY_EXIT_IF_NULL(ifus = kmo_identify_values(ifus_txt));
00903             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_science_frames,
00904                     CPL_ERROR_ILLEGAL_INPUT,
00905                     "ifus parameter must have the same number of values than"
00906                     "frames provided (for frames just containing "
00907                     "skies insert 0)) (%lld!=%d)",
00908                     cpl_vector_get_size(ifus), nr_science_frames);
00909         }
00910 
00911         if (strcmp(name, "") != 0) {
00912             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
00913                     "ifus parameter must be NULL if name is provided!");
00914         }
00915 
00916         KMO_TRY_EXIT_IF_ERROR(
00917             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.ifus"));
00918 
00919         KMO_TRY_EXIT_IF_ERROR(
00920             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.name"));
00921 
00922         kmos_band_pars_load(parlist, "kmos.kmo_sci_red");
00923 
00924         extrapolate = kmo_dfs_get_parameter_bool(parlist, 
00925                 "kmos.kmo_sci_red.extrapolate");
00926         KMO_TRY_CHECK_ERROR_STATE();
00927 
00928         if (strcmp(smethod, "NN") == 0) {
00929             if (extrapolate == TRUE) {
00930                 cpl_msg_warning(__func__, 
00931                         "extrapolation for smethod='NN' not available!");
00932             }
00933             extrapol_enum = NONE_NANS;
00934         } else if (strcmp(smethod, "CS") == 0) {
00935             if (extrapolate == FALSE) {
00936                 extrapol_enum = NONE_NANS;
00937             } else if (extrapolate == TRUE) {
00938                 extrapol_enum = BCS_NATURAL;
00939             } else {
00940                 KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
00941                         "extrapolate must be either FALSE or TRUE");
00942             }
00943             smethod = "BCS";
00944         } else {
00945             KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
00946                     "smethod must be either \"CS\" or \"NN\"");
00947         }
00948         KMO_TRY_CHECK_ERROR_STATE();
00949 
00950         KMO_TRY_EXIT_IF_ERROR(
00951             kmo_dfs_print_parameter_help(parlist, 
00952                 "kmos.kmo_sci_red.extrapolate"));
00953 
00954         fast_mode = kmo_dfs_get_parameter_bool(parlist, 
00955                 "kmos.kmo_sci_red.fast_mode");
00956         KMO_TRY_CHECK_ERROR_STATE();
00957         KMO_TRY_ASSURE((fast_mode == TRUE) || (fast_mode == FALSE),
00958                 CPL_ERROR_ILLEGAL_INPUT, "fast_mode is either FALSE or TRUE");
00959         KMO_TRY_EXIT_IF_ERROR(
00960             kmo_dfs_print_parameter_help(parlist,"kmos.kmo_sci_red.fast_mode"));
00961         edge_nan = kmo_dfs_get_parameter_bool(parlist, 
00962                 "kmos.kmo_sci_red.edge_nan");
00963         KMO_TRY_CHECK_ERROR_STATE();
00964         KMO_TRY_EXIT_IF_ERROR(
00965             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.edge_nan"));
00966         KMO_TRY_ASSURE((edge_nan == TRUE) || (edge_nan == FALSE),
00967                 CPL_ERROR_ILLEGAL_INPUT, "edge_nan must be TRUE or FALSE");
00968         no_combine = kmo_dfs_get_parameter_bool(parlist, 
00969                 "kmos.kmo_sci_red.no_combine");
00970         KMO_TRY_CHECK_ERROR_STATE();
00971         KMO_TRY_EXIT_IF_ERROR(
00972             kmo_dfs_print_parameter_help(parlist,
00973                 "kmos.kmo_sci_red.no_combine"));
00974         KMO_TRY_ASSURE((no_combine == TRUE) || (no_combine == FALSE),
00975                 CPL_ERROR_ILLEGAL_INPUT, "no_combine must be TRUE or FALSE!");
00976         no_subtract = kmo_dfs_get_parameter_bool(parlist, 
00977                 "kmos.kmo_sci_red.no_subtract");
00978         KMO_TRY_CHECK_ERROR_STATE();
00979         KMO_TRY_EXIT_IF_ERROR(
00980             kmo_dfs_print_parameter_help(parlist, 
00981                 "kmos.kmo_sci_red.no_subtract"));
00982         KMO_TRY_ASSURE((no_subtract == TRUE) || (no_subtract == FALSE),
00983                 CPL_ERROR_ILLEGAL_INPUT, "no_subtract must be TRUE or FALSE");
00984         sky_tweak = kmo_dfs_get_parameter_bool(parlist, 
00985                 "kmos.kmo_sci_red.sky_tweak");
00986         KMO_TRY_CHECK_ERROR_STATE();
00987         KMO_TRY_EXIT_IF_ERROR(
00988             kmo_dfs_print_parameter_help(parlist,"kmos.kmo_sci_red.sky_tweak"));
00989         KMO_TRY_ASSURE((sky_tweak == TRUE) || (sky_tweak == FALSE),
00990                 CPL_ERROR_ILLEGAL_INPUT, "sky_tweak must be TRUE or FALSE");
00991         KMO_TRY_ASSURE(!((no_subtract == TRUE) && (sky_tweak == TRUE)),
00992                 CPL_ERROR_ILLEGAL_INPUT,
00993                 "Either no_subtract or sky_tweak or both must be FALSE (try instead sky_tweak and save_interims)!");
00994         tbsub = kmo_dfs_get_parameter_bool(parlist, "kmos.kmo_sci_red.tbsub");
00995         KMO_TRY_CHECK_ERROR_STATE();
00996 
00997         pix_scale = kmo_dfs_get_parameter_double(parlist,
00998                 "kmos.kmo_sci_red.pix_scale");
00999         KMO_TRY_CHECK_ERROR_STATE();
01000         KMO_TRY_EXIT_IF_ERROR(
01001            kmo_dfs_print_parameter_help(parlist, "kmos.kmo_sci_red.pix_scale"));
01002         KMO_TRY_ASSURE((pix_scale >= 0.01) && (pix_scale <= 0.4),
01003                 CPL_ERROR_ILLEGAL_INPUT,
01004                 "pix_scale must be between 0.01 and 0.4 (results in cubes "
01005                 "with 7x7 to 280x280 pixels)!");
01006         xcal_interpolation = kmo_dfs_get_parameter_bool(parlist,
01007                 "kmos.kmo_sci_red.xcal_interpolation");
01008         KMO_TRY_CHECK_ERROR_STATE();
01009         KMO_TRY_EXIT_IF_ERROR(
01010             kmo_dfs_print_parameter_help(parlist,
01011                 "kmos.kmo_sci_red.xcal_interpolation"));
01012         KMO_TRY_ASSURE((xcal_interpolation == TRUE) ||
01013                 (xcal_interpolation == FALSE),
01014                 CPL_ERROR_ILLEGAL_INPUT,
01015                 "xcal_interpolation must be TRUE or FALSE!");
01016         suppress_extension = kmo_dfs_get_parameter_bool(parlist,
01017                 "kmos.kmo_sci_red.suppress_extension");
01018         KMO_TRY_CHECK_ERROR_STATE();
01019         KMO_TRY_EXIT_IF_ERROR(
01020             kmo_dfs_print_parameter_help(parlist, 
01021                 "kmos.kmo_sci_red.suppress_extension"));
01022         KMO_TRY_ASSURE((suppress_extension == TRUE) || 
01023                 (suppress_extension == FALSE),
01024                 CPL_ERROR_ILLEGAL_INPUT,
01025                 "suppress_extension must be TRUE or FALSE!");
01026         fn_obj_sky_table = kmo_dfs_get_parameter_string(parlist, 
01027                 "kmos.kmo_sci_red.obj_sky_table");
01028         KMO_TRY_CHECK_ERROR_STATE();
01029         KMO_TRY_EXIT_IF_ERROR(
01030             kmo_dfs_print_parameter_help(parlist, 
01031                 "kmos.kmo_sci_red.obj_sky_table"));
01032         KMO_TRY_EXIT_IF_ERROR(
01033             kmos_combine_pars_load(parlist, "kmos.kmo_sci_red", &cmethod,
01034                 &cpos_rej, &cneg_rej, &citer, &cmin, &cmax, FALSE));
01035         velo_offset = kmo_dfs_get_parameter_double(parlist, 
01036                 "kmos.kmo_sci_red.velocity_offset");
01037         KMO_TRY_CHECK_ERROR_STATE();
01038 
01039         velo_corr = 1. + velo_offset * 1000. / CPL_PHYS_C;
01040         velo_corr_ptr = &velo_corr;
01041         KMO_TRY_EXIT_IF_ERROR(
01042             kmo_dfs_print_parameter_help(parlist,
01043                 "kmos.kmo_sci_red.velocity_offset"));
01044         save_interims = kmo_dfs_get_parameter_bool(parlist,
01045                 "kmos.kmo_sci_red.save_interims");
01046         KMO_TRY_CHECK_ERROR_STATE();
01047         KMO_TRY_ASSURE((save_interims == TRUE) || (save_interims == FALSE),
01048                 CPL_ERROR_ILLEGAL_INPUT, "save_interims must be TRUE or FALSE");
01049         KMO_TRY_ASSURE(!((save_interims == TRUE) && (sky_tweak == FALSE)),
01050                 CPL_ERROR_ILLEGAL_INPUT,
01051                "Save_interims saves sky_tweak objects so sky_tweak must be enabled too");
01052         KMO_TRY_EXIT_IF_ERROR(
01053             kmo_dfs_print_parameter_help(parlist, 
01054                 "kmos.kmo_sci_red.save_interims"));
01055         cpl_msg_info("", "-------------------------------------------");
01056 
01057         // assure that filters, grating and rotation offsets match for
01058         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
01059         // frames)
01060         /* Check if filter_id and grating_id match for all detectors */
01061         KMO_TRY_EXIT_IF_ERROR(
01062             kmo_check_frameset_setup(frameset, SCIENCE, TRUE, FALSE, TRUE));
01063         KMO_TRY_EXIT_IF_ERROR(
01064             kmo_check_frame_setup(frameset, SCIENCE, YCAL, TRUE, FALSE, TRUE));
01065         KMO_TRY_EXIT_IF_ERROR(
01066             kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE));
01067         KMO_TRY_EXIT_IF_ERROR(
01068             kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE));
01069         if (has_master_flat) {
01070             KMO_TRY_EXIT_IF_ERROR(kmo_check_frame_setup(frameset, XCAL,
01071                         MASTER_FLAT, TRUE, FALSE, TRUE));
01072         }
01073         if (has_telluric) {
01074             KMO_TRY_EXIT_IF_ERROR(kmo_check_frame_setup(frameset, XCAL, 
01075                         TELLURIC, TRUE, FALSE, TRUE));
01076         }
01077         if (has_oh_spec) {
01078             KMO_TRY_EXIT_IF_ERROR(kmo_check_oh_spec_setup(frameset, XCAL));
01079         }
01080 
01081         // check descriptors of all frames
01082         KMO_TRY_EXIT_IF_NULL(xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
01083 
01084         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
01085         KMO_TRY_CHECK_ERROR_STATE();
01086 
01087         KMO_TRY_ASSURE((desc1.nr_ext % KMOS_NR_DETECTORS == 0) &&
01088                 (desc1.ex_badpix == FALSE) &&
01089                 (desc1.fits_type == f2d_fits) &&
01090                 (desc1.frame_type == detector_frame),
01091                 CPL_ERROR_ILLEGAL_INPUT,
01092                 "XCAL isn't in the correct format!!!");
01093 
01094         KMO_TRY_EXIT_IF_NULL(ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
01095         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
01096         KMO_TRY_CHECK_ERROR_STATE();
01097 
01098         KMO_TRY_ASSURE((desc1.nr_ext == desc2.nr_ext) &&
01099                (desc1.ex_badpix == desc2.ex_badpix) &&
01100                (desc1.fits_type == desc2.fits_type) &&
01101                (desc1.frame_type == desc2.frame_type),
01102                CPL_ERROR_ILLEGAL_INPUT,
01103                "YCAL isn't in the correct format!!!");
01104         kmo_free_fits_desc(&desc2);
01105         kmo_init_fits_desc(&desc2);
01106 
01107         KMO_TRY_EXIT_IF_NULL(lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
01108         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
01109         KMO_TRY_CHECK_ERROR_STATE();
01110 
01111         KMO_TRY_ASSURE((desc2.nr_ext % KMOS_NR_DETECTORS == 0) &&
01112                (desc1.ex_badpix == desc2.ex_badpix) &&
01113                (desc1.fits_type == desc2.fits_type) &&
01114                (desc1.frame_type == desc2.frame_type),
01115                CPL_ERROR_ILLEGAL_INPUT,
01116                "LCAL isn't in the correct format!!!");
01117         kmo_free_fits_desc(&desc2);
01118         kmo_init_fits_desc(&desc2);
01119 
01120         if (has_master_flat) {
01121             KMO_TRY_EXIT_IF_NULL(flat_frame = kmo_dfs_get_frame(frameset, 
01122                         MASTER_FLAT));
01123             desc2=kmo_identify_fits_header(cpl_frame_get_filename(flat_frame));
01124             KMO_TRY_CHECK_ERROR_STATE();
01125 
01126             KMO_TRY_ASSURE((desc2.nr_ext % (2*KMOS_NR_DETECTORS) == 0) &&
01127                     (desc1.ex_badpix == desc2.ex_badpix) &&
01128                     (desc1.fits_type == desc2.fits_type) &&
01129                     (desc1.frame_type == desc2.frame_type),
01130                     CPL_ERROR_ILLEGAL_INPUT,
01131                     "MASTER_FLAT isn't in the correct format!!!");
01132             kmo_free_fits_desc(&desc2);
01133             kmo_init_fits_desc(&desc2);
01134         }
01135 
01136         if (has_illum_corr) {
01137             KMO_TRY_EXIT_IF_NULL(illum_frame = kmo_dfs_get_frame(frameset,
01138                         ILLUM_CORR));
01139             desc2=kmo_identify_fits_header(cpl_frame_get_filename(illum_frame));
01140             KMO_TRY_CHECK_ERROR_STATE();
01141             KMO_TRY_ASSURE(((desc2.nr_ext == 24) || (desc2.nr_ext == 48)) &&
01142                     (desc2.ex_badpix == FALSE) &&
01143                     (desc2.fits_type == f2i_fits) &&
01144                     (desc2.frame_type == ifu_frame),
01145                     CPL_ERROR_ILLEGAL_INPUT,
01146                     "ILLUM_CORR isn't in the correct format!!!");
01147             kmo_free_fits_desc(&desc2);
01148             kmo_init_fits_desc(&desc2);
01149         }
01150 
01151         if (has_telluric) {
01152             KMO_TRY_EXIT_IF_NULL(telluric_frame = kmo_dfs_get_frame(frameset, 
01153                         TELLURIC));
01154             desc_telluric=kmo_identify_fits_header(
01155                     cpl_frame_get_filename(telluric_frame));
01156             KMO_TRY_CHECK_ERROR_STATE();
01157             KMO_TRY_ASSURE(((desc_telluric.nr_ext == 24) ||
01158                         (desc_telluric.nr_ext == 48)) &&
01159                     (desc_telluric.ex_badpix == FALSE) &&
01160                     (desc_telluric.fits_type == f1i_fits) &&
01161                     (desc_telluric.frame_type == ifu_frame),
01162                     CPL_ERROR_ILLEGAL_INPUT,
01163                     "TELLURIC isn't in the correct format!!!");
01164         }
01165         kmo_free_fits_desc(&desc2);
01166 
01167         KMO_TRY_EXIT_IF_NULL(tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
01168         while (tmp_frame != NULL ) {
01169             desc2 = kmo_identify_fits_header(cpl_frame_get_filename(tmp_frame));
01170             KMO_TRY_CHECK_ERROR_STATE();
01171             KMO_TRY_ASSURE((desc2.nr_ext == 3) &&
01172                     (desc2.ex_badpix == FALSE) &&
01173                     (desc2.fits_type == raw_fits) &&
01174                     (desc2.frame_type == detector_frame),
01175                     CPL_ERROR_ILLEGAL_INPUT,
01176                     "SCIENCE isn't in the correct format");
01177             kmo_free_fits_desc(&desc2);
01178             kmo_init_fits_desc(&desc2);
01179 
01180             if (mapping_mode == NULL) {
01181                 KMO_TRY_EXIT_IF_NULL(
01182                     tmp_header = kmclipm_propertylist_load(
01183                         cpl_frame_get_filename(tmp_frame), 0));
01184                 if (cpl_propertylist_has(tmp_header, TPL_ID)) {
01185                     KMO_TRY_EXIT_IF_NULL(tmp_str = 
01186                             cpl_propertylist_get_string(tmp_header, TPL_ID));
01187                     if (strcmp(tmp_str, MAPPING8) == 0) {
01188                         mapping_mode = cpl_sprintf("%s", "mapping8");
01189                     }
01190                     if (strcmp(tmp_str, MAPPING24) == 0) {
01191                         mapping_mode = cpl_sprintf("%s", "mapping24");
01192                     }
01193                 }
01194                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01195             }
01196             tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01197             KMO_TRY_CHECK_ERROR_STATE();
01198         }
01199 
01200         if (mapping_mode != NULL) {
01201             // we are in mapping mode
01202             if ((ifus != NULL) || (strcmp(name, "") != 0)) {
01203                 cpl_msg_warning(__func__,
01204                         "The SCIENCE frames have been taken in one of the "
01205                         "mapping modes AND specific IFUs have been "
01206                         "specified! --> Only processing these!");
01207             } else {
01208                 if (strcmp(smethod, "BCS") == 0) {
01209                     extrapol_enum = BCS_NATURAL;
01210                     cpl_msg_info(__func__,
01211                             "Detected frames taken in mapping mode. "
01212                             "Changing extrapolation mode to TRUE.");
01213                 }
01214             }
01215             if (fast_mode) {
01216                 cpl_msg_info(__func__, "Creating map in fast_mode.");
01217             }
01218         } else {
01219             if (fast_mode) {
01220                 cpl_msg_info(__func__, 
01221                         "fast_mode has been selected but we aren't in "
01222                         "mapping mode. The choice for fast_mode is ignored.");
01223             }
01224         }
01225 
01226         KMO_TRY_EXIT_IF_NULL(
01227             suffix = kmo_dfs_get_suffix(xcal_frame, TRUE, FALSE));
01228 
01229         /* Verify that XCAL / YCAL were generated together */
01230         KMO_TRY_EXIT_IF_ERROR(kmo_check_frame_setup_md5_xycal(frameset));
01231         /* Verify that XCAL and YCAL / LCAL were generated together */
01232         KMO_TRY_EXIT_IF_ERROR(kmo_check_frame_setup_md5(frameset));
01233         /* b_start/b_end/b_samples used for LCAL and TELLURIC were the same */
01234         KMO_TRY_EXIT_IF_ERROR(kmo_check_frame_setup_sampling(frameset));
01235 
01236         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
01237         cpl_msg_info("", "(grating 1, 2 & 3)");
01238 
01239         /* Check which IFUs are active for all frames */
01240         KMO_TRY_EXIT_IF_NULL(unused_ifus_before = 
01241                 kmo_get_unused_ifus(frameset, 1, 1));
01242         KMO_TRY_EXIT_IF_NULL(unused_ifus_after = 
01243                 kmo_duplicate_unused_ifus(unused_ifus_before));
01244         kmo_print_unused_ifus(unused_ifus_before, FALSE);
01245 
01246         /* Get bounds, setup grid, setup arm_name-struct */
01247         /* Get left and right bounds of IFUs from XCAL */
01248         KMO_TRY_EXIT_IF_NULL(
01249             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
01250         KMO_TRY_EXIT_IF_NULL(bounds = kmclipm_extract_bounds(tmp_header));
01251         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01252 
01253         /* Setup grid definition, wavelength start and end points will be */
01254         /* set in the detector loop */
01255         KMO_TRY_EXIT_IF_ERROR(
01256             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.));
01257 
01258         /*
01259             Create armNameStruct : Contains info about objects that need
01260             to be reconstructed and for each of them which sky need to be used
01261             Get valid STD frames with objects in it and associated sky 
01262             exposures and get valid object names to process, either one object
01263             name across several SCIENCE frames, or all object names
01264         */
01265         if (strcmp(fn_obj_sky_table, "") == 0) {
01266             KMO_TRY_EXIT_IF_NULL(
01267                 arm_name_struct = kmo_create_armNameStruct(frameset, SCIENCE,
01268                     ifus, name, unused_ifus_after, bounds, mapping_mode,
01269                     no_subtract));
01270             KMO_TRY_EXIT_IF_ERROR(
01271                 kmo_save_objSkyStruct(arm_name_struct->obj_sky_struct));
01272         } else {
01273             // read in obj/sky-table
01274             objSkyStruct *obj_sky_struct = NULL;
01275 
01276             KMO_TRY_EXIT_IF_NULL(
01277                 obj_sky_struct = kmo_read_objSkyStruct(fn_obj_sky_table,
01278                     frameset, SCIENCE));
01279 
01280             /* Check if any sky-IFUs have been specified not beeing the */
01281             /* same IFU# for objects. */
01282             // In this case sky_tweak must be activated
01283             for (i = 0; i < obj_sky_struct->size; i++) {
01284                 if (obj_sky_struct->table[i].objFrame != NULL) {
01285                     for (jj = 0; jj < KMOS_NR_IFUS; jj++) {
01286                         if ((obj_sky_struct->table[i].skyIfus[jj] > 0) && 
01287                                 (sky_tweak == FALSE)) {
01288                             kmo_print_objSkyStruct(obj_sky_struct);
01289 
01290                             cpl_msg_error("","*************************************************************************");
01291                             cpl_msg_error("","*  The provided obj/sky-association-table (parameter --obj_sky_table)   *");
01292                             cpl_msg_error("","*  contains skies assigned to objects originating from different IFUs!  *");
01293                             cpl_msg_error("","*  In this case the parameter --sky_tweak has to be set by the user!    *");
01294                             cpl_msg_error("","*************************************************************************");
01295 
01296                             kmo_delete_objSkyStruct(obj_sky_struct);
01297                             KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT," ");
01298                         }
01299                     }
01300                 }
01301             }
01302 
01303             KMO_TRY_EXIT_IF_NULL(
01304                 arm_name_struct = kmo_create_armNameStruct2(obj_sky_struct,
01305                     frameset, SCIENCE, ifus, name, unused_ifus_after, bounds,
01306                     mapping_mode, no_subtract));
01307         }
01308         kmo_print_armNameStruct(frameset, arm_name_struct);
01309 
01310         /* Check Telluric availability for each Object */
01311         /* Why only mapping  ? Not clear */
01312         /* in mapping-mode check if for all IFUs there is either no  */
01313         /* telluric at all or the same number of tellurics than object names */
01314         if ((has_telluric) && (mapping_mode != NULL)) {
01315             telluric_ok = TRUE;
01316             for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01317                 if (!((arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj]) ||
01318                     (arm_name_struct->telluricCnt[jj] == 0))) {
01319                     telluric_ok = FALSE;
01320                     break;
01321                 }
01322             }
01323             if (!telluric_ok) {
01324                 KMO_TRY_ASSURE(1==0, CPL_ERROR_UNSUPPORTED_MODE,
01325                         "Mosaics need a TELLURIC frame with at least a telluric correction per detector available! "
01326                         "Omit the TELLURIC from your sof-file or choose another TELLURIC!");
01327             }
01328         }
01329 
01330         /* Load lcal-frames */
01331         KMO_TRY_EXIT_IF_NULL(lcal = (cpl_image**)cpl_calloc(KMOS_NR_DETECTORS, 
01332                     sizeof(cpl_image*)));
01333         for (i = 0; i < KMOS_NR_DETECTORS; i++) {
01334             KMO_TRY_EXIT_IF_NULL(lcal[i] = kmo_dfs_load_image(frameset, LCAL, 
01335                         i+1, FALSE, FALSE, NULL));
01336         }
01337 
01338         nr_data_alloc = KMOS_NR_IFUS;
01339         KMO_TRY_EXIT_IF_NULL(cube_data = (cpl_imagelist**)cpl_calloc(
01340                     nr_data_alloc, sizeof(cpl_imagelist*)));
01341         KMO_TRY_EXIT_IF_NULL(cube_noise = (cpl_imagelist**)cpl_calloc(
01342                     nr_data_alloc, sizeof(cpl_imagelist*)));
01343         KMO_TRY_EXIT_IF_NULL(header_data = (cpl_propertylist**)cpl_calloc(
01344                     nr_data_alloc, sizeof(cpl_propertylist*)));
01345         KMO_TRY_EXIT_IF_NULL(header_noise = (cpl_propertylist**)cpl_calloc(
01346                     nr_data_alloc, sizeof(cpl_propertylist*)));
01347 
01348         if (save_interims) {
01349             KMO_TRY_EXIT_IF_NULL(cube_interim_object=(cpl_imagelist**)cpl_calloc(
01350                         nr_data_alloc, sizeof(cpl_imagelist*)));
01351             KMO_TRY_EXIT_IF_NULL(cube_interim_sky =(cpl_imagelist**)cpl_calloc(
01352                         nr_data_alloc, sizeof(cpl_imagelist*)));
01353             KMO_TRY_EXIT_IF_NULL(header_sky = (cpl_propertylist**)cpl_calloc(
01354                         nr_data_alloc, sizeof(cpl_propertylist*)));
01355         }
01356 
01357         if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
01358             no_combine = TRUE;
01359             cpl_msg_info(__func__, 
01360                     "--no_combine set to TRUE since there is 1 SCIENCE frame");
01361         }
01362 
01363         if (no_subtract) {
01364             no_combine = TRUE;
01365             cpl_msg_info(__func__, 
01366                     "--no_combine set to TRUE since --no_subtract is set");
01367         }
01368         actual_msg_level = cpl_msg_get_level();
01369         cpl_msg_info("", "-------------------------------------------");
01370 
01371         /* Check if input SCIENCE frames are really ALL observations */
01372         /* If not, Omit the OH_SPEC, even if it is passed - issue a Warning */
01373         if (has_oh_spec) {
01374             int is_all_obs          = TRUE,
01375                 has_all_origfile    = TRUE;
01376 
01377             KMO_TRY_EXIT_IF_NULL(
01378                 tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
01379             while (tmp_frame != NULL ) {
01380                 KMO_TRY_EXIT_IF_NULL(tmp_header = kmclipm_propertylist_load(
01381                             cpl_frame_get_filename(tmp_frame), 0));
01382                 if (cpl_propertylist_has(tmp_header, ORIGFILE)) {
01383                     KMO_TRY_EXIT_IF_NULL(tmp_str = 
01384                             cpl_propertylist_get_string(tmp_header, ORIGFILE));
01385                     if (strstr(tmp_str, "OBS") == NULL) {
01386                         is_all_obs = FALSE;
01387                     }
01388                 } else {
01389                     has_all_origfile = FALSE;
01390                 }
01391                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01392                 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01393                 KMO_TRY_CHECK_ERROR_STATE();
01394             }
01395 
01396             if (has_all_origfile) {
01397                 if (is_all_obs) {
01398                     /* OBS-frame reconstruction - allow OH_SPEC */
01399                     KMO_TRY_EXIT_IF_NULL(ref_spectrum_frame = 
01400                             kmo_dfs_get_frame(frameset, OH_SPEC));
01401 
01402                     /* Verify OH_SPEC */
01403                     /* TODO */
01404 
01405                 } else {
01406                     cpl_msg_warning(__func__, 
01407                             "Supplied OH_SPEC is ignored since a calibration "
01408                             "frame is being used as SCIENCE frame.");
01409                 }
01410             } else {
01411                 cpl_msg_warning(__func__, 
01412                         "Supplied OH_SPEC is ignored since a calibration "
01413                         "frame is being used as SCIENCE frame.");
01414             }
01415         }
01416 
01417         /* Loop all science frames containing at least one object */
01418         cpl_msg_info(__func__, "Reconstructing & saving cubes with objects");
01419         for (sf = 0; sf < arm_name_struct->size; sf++) {
01420             KMO_TRY_EXIT_IF_NULL(fn_obj = cpl_frame_get_filename(
01421                         arm_name_struct->obj_sky_struct->table[sf].objFrame));
01422             KMO_TRY_EXIT_IF_NULL(
01423                 main_header = kmclipm_propertylist_load(fn_obj, 0));
01424             actual_msg_level = cpl_msg_get_level();
01425 
01426             /* Reconstruct science frame */
01427             cpl_msg_info(__func__, "   > processing frame: %s", fn_obj);
01428             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01429                 sky_ifu_nr = ifu_nr;
01430                 det_nr = (ifu_nr - 1)/KMOS_IFUS_PER_DETECTOR + 1;
01431 
01432                 KMO_TRY_ASSURE((det_nr >= 1) && (det_nr <= KMOS_NR_DETECTORS),
01433                         CPL_ERROR_ILLEGAL_INPUT,
01434                         "The provided ifu-numbers are incorrect! They "
01435                         "must be between 1 and %d", KMOS_NR_IFUS);
01436 
01437                 /* Get subheader data */
01438                 KMO_TRY_EXIT_IF_NULL(header_data[ifu_nr-1] = 
01439                         kmclipm_propertylist_load(fn_obj, det_nr));
01440                 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(ifu_frame, 
01441                             ifu_nr, EXT_DATA));
01442                 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
01443                             header_data[ifu_nr-1], EXTNAME, extname,
01444                             "FITS extension name"));
01445                 cpl_free(extname); extname = NULL;
01446 
01447                 if (arm_name_struct->name_ids[ifu_nr-1+sf*KMOS_NR_IFUS] >= 1) {
01448                     // IFU is valid
01449 
01450                     /* Fill do_sky_subtraction and sky_frame */
01451                     if ((arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1] != NO_CORRESPONDING_SKYFRAME) && !no_subtract) {
01452                         do_sky_subtraction = TRUE;
01453                         if (no_subtract) {
01454                             sky_frame = NULL;
01455                         } else {
01456                             sky_frame = arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1];
01457                             KMO_TRY_EXIT_IF_NULL(
01458                                 fn_sky = cpl_frame_get_filename(sky_frame));
01459                         }
01460 
01461                         if (sky_tweak){
01462                             sky_as_object_frame = sky_frame;
01463                             sky_frame = NULL;
01464                             /* printf("a - %d\n", sky_ifu_nr) ; */
01465                             sky_ifu_nr = arm_name_struct->obj_sky_struct->table[sf].skyIfus[ifu_nr-1];
01466                             /* printf("b - %d\n", sky_ifu_nr) ; */
01467                         }
01468 
01469                         if (no_subtract) {
01470                             cpl_msg_warning(__func__, 
01471                                     "      > Omit sky subtraction on IFU %d", 
01472                                     ifu_nr);
01473                         } else {
01474                             if (sky_ifu_nr == ifu_nr) {
01475                                 cpl_msg_info(__func__, 
01476                                         "      > IFU %d (sky in frame: %s)",
01477                                         ifu_nr, fn_sky);
01478                             } else {
01479                                 cpl_msg_info(__func__, 
01480                                         "      > IFU %d (sky in IFU %d of frame: %s)",
01481                                         ifu_nr, sky_ifu_nr, fn_sky);
01482                             }
01483                         }
01484                     } else {
01485                         do_sky_subtraction = FALSE;
01486                         sky_frame = NULL;
01487                         if (!no_subtract) {
01488                             cpl_msg_warning(__func__, 
01489                                     "      > IFU %d with no corresponding sky frame", 
01490                                     ifu_nr);
01491                         }
01492                     }
01493 
01494                     /* Get filter for this detector and setup grid definition using WAVE_BAND */
01495                     KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s", 
01496                                 IFU_FILTID_PREFIX, det_nr, IFU_FILTID_POSTFIX));
01497                     KMO_TRY_EXIT_IF_NULL(filter_id = 
01498                             cpl_propertylist_get_string(main_header, keyword));
01499                     cpl_free(keyword); keyword = NULL;
01500 
01501                     /* TODO : Review print_once mechanism */
01502                     /* Used to print once per detector - problematic for parallelisation */
01503                     if (print_once)     cpl_msg_set_level(CPL_MSG_WARNING);
01504 
01505                     KMO_TRY_EXIT_IF_NULL(band_table = kmo_dfs_load_table(
01506                                 frameset, WAVE_BAND, 1, 0));
01507                     KMO_TRY_EXIT_IF_ERROR(kmclipm_setup_grid_band_lcal(&gd, 
01508                                 filter_id, band_table));
01509                     cpl_table_delete(band_table); band_table = NULL;
01510 
01511                     print_once = TRUE;
01512                     cpl_msg_set_level(actual_msg_level);
01513 
01514                     /* calc WCS & update subheader */
01515                     KMO_TRY_EXIT_IF_ERROR(kmo_calc_wcs_gd(main_header, 
01516                                 header_data[ifu_nr-1], ifu_nr, gd));
01517 
01518                     /* Update some keywords  */
01519                     KMO_TRY_EXIT_IF_ERROR(
01520                         kmclipm_update_property_int(header_data[ifu_nr-1],
01521                             NAXIS, 3, "number of data axes"));
01522                     KMO_TRY_EXIT_IF_ERROR(
01523                         kmclipm_update_property_int(header_data[ifu_nr-1],
01524                             NAXIS1, gd.x.dim, "length of data axis 1"));
01525                     KMO_TRY_EXIT_IF_ERROR(
01526                         kmclipm_update_property_int(header_data[ifu_nr-1],
01527                             NAXIS2, gd.y.dim, "length of data axis 2"));
01528                     KMO_TRY_EXIT_IF_ERROR(
01529                         kmclipm_update_property_int(header_data[ifu_nr-1],
01530                             NAXIS3, gd.l.dim, "length of data axis 3"));
01531 
01532                     /* Option save_interim only applies if sky_tweak is used */
01533                     if (save_interims && (sky_as_object_frame != NULL)) {
01534                         KMO_TRY_EXIT_IF_NULL(
01535                                 main_sky_header = kmclipm_propertylist_load(
01536                                         cpl_frame_get_filename(
01537                                             sky_as_object_frame), 0));
01538                         KMO_TRY_EXIT_IF_NULL(
01539                                 header_sky[ifu_nr-1]=kmclipm_propertylist_load(
01540                                     cpl_frame_get_filename(
01541                                         sky_as_object_frame), det_nr));
01542                         KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(
01543                                     ifu_frame, ifu_nr, EXT_DATA));
01544                         KMO_TRY_EXIT_IF_ERROR(
01545                                 kmclipm_update_property_string(
01546                                     header_sky[ifu_nr-1], EXTNAME, extname,
01547                                     "FITS extension name"));
01548                         cpl_free(extname); extname = NULL;
01549 
01550                         KMO_TRY_EXIT_IF_ERROR(kmo_calc_wcs_gd(main_sky_header,
01551                                     header_sky[ifu_nr-1], ifu_nr, gd));
01552 
01553                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01554                                     header_sky[ifu_nr-1], NAXIS, 3,
01555                                     "number of data axes"));
01556                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01557                                     header_sky[ifu_nr-1], NAXIS1, gd.x.dim,
01558                                     "length of data axis 1"));
01559                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01560                                     header_sky[ifu_nr-1], NAXIS2, gd.y.dim,
01561                                     "length of data axis 2"));
01562                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01563                                     header_sky[ifu_nr-1], NAXIS3, gd.l.dim,
01564                                     "length of data axis 3"));
01565                         cpl_propertylist_delete(main_sky_header); 
01566                         main_sky_header = NULL;
01567                     }
01568 
01569                     /* Reconstruct object */
01570                     if (ref_spectrum_frame == NULL) {
01571                         /* No lambda correction using OH lines */
01572                         KMO_TRY_EXIT_IF_ERROR(
01573                                 kmo_reconstruct_sci(
01574                                     ifu_nr,
01575                                     bounds[2*(ifu_nr-1)],
01576                                     bounds[2*(ifu_nr-1)+1],
01577                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01578                                     SCIENCE,
01579                                     sky_frame,
01580                                     SCIENCE,
01581                                     flat_frame,
01582                                     xcal_frame,
01583                                     ycal_frame,
01584                                     lcal_frame,
01585                                     NULL,
01586                                     velo_corr_ptr,
01587                                     &gd,
01588                                     &cube_data[ifu_nr-1],
01589                                     &cube_noise[ifu_nr-1],
01590                                     flux,
01591                                     background,
01592                                     xcal_interpolation));
01593                     } else { 
01594                         /* Lambda correction using OH lines */
01595                         KMO_TRY_EXIT_IF_ERROR(
01596                                 kmo_reconstruct_sci(
01597                                     ifu_nr,
01598                                     bounds[2*(ifu_nr-1)],
01599                                     bounds[2*(ifu_nr-1)+1],
01600                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01601                                     SCIENCE,
01602                                     NULL,
01603                                     NULL,
01604                                     flat_frame,
01605                                     xcal_frame,
01606                                     ycal_frame,
01607                                     lcal_frame,
01608                                     NULL,
01609                                     NULL,
01610                                     &gd,
01611                                     &cube_data[ifu_nr-1],
01612                                     &cube_noise[ifu_nr-1],
01613                                     FALSE,
01614                                     FALSE,
01615                                     xcal_interpolation));
01616                         if (cube_data[ifu_nr-1] != NULL) {
01617                             KMO_TRY_EXIT_IF_NULL(
01618                                 oh_lcorr_coeffs = kmo_lcorr_get(
01619                                     cube_data[ifu_nr-1], header_data[ifu_nr-1],
01620                                     ref_spectrum_frame, gd, filter_id, ifu_nr));
01621                             cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01622                             cube_data[ifu_nr-1] = NULL;
01623                             if (cube_noise[ifu_nr-1] != NULL) {
01624                                 cpl_imagelist_delete(cube_noise[ifu_nr-1]); 
01625                                 cube_noise[ifu_nr-1] = NULL;
01626                             }
01627 
01628                             KMO_TRY_EXIT_IF_ERROR(
01629                                     kmo_reconstruct_sci(
01630                                         ifu_nr,
01631                                         bounds[2*(ifu_nr-1)],
01632                                         bounds[2*(ifu_nr-1)+1],
01633                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01634                                         SCIENCE,
01635                                         sky_frame,
01636                                         SCIENCE,
01637                                         flat_frame,
01638                                         xcal_frame,
01639                                         ycal_frame,
01640                                         lcal_frame,
01641                                         oh_lcorr_coeffs,
01642                                         velo_corr_ptr,
01643                                         &gd,
01644                                         &cube_data[ifu_nr-1],
01645                                         &cube_noise[ifu_nr-1],
01646                                         flux,
01647                                         background,
01648                                         xcal_interpolation));
01649                             cpl_polynomial_delete(oh_lcorr_coeffs); 
01650                             oh_lcorr_coeffs = NULL;
01651                         }
01652                     }
01653 
01654                     /* If sky_tweak is set,reconstruct sky frame as object */
01655                     /* and  use kmo_priv_sky_tweak to subtract  */
01656                     /* a modified sky cube */
01657                     if (do_sky_subtraction && sky_tweak) {
01658                         if (ref_spectrum_frame == NULL) {
01659                             /* No lambda correction using OH lines */
01660                             KMO_TRY_EXIT_IF_ERROR(
01661                                     kmo_reconstruct_sci(
01662                                         sky_ifu_nr,
01663                                         bounds[2*(sky_ifu_nr-1)],
01664                                         bounds[2*(sky_ifu_nr-1)+1],
01665                                         sky_as_object_frame,
01666                                         SCIENCE,
01667                                         sky_frame,
01668                                         SCIENCE,
01669                                         flat_frame,
01670                                         xcal_frame,
01671                                         ycal_frame,
01672                                         lcal_frame,
01673                                         NULL,
01674                                         velo_corr_ptr,
01675                                         &gd,
01676                                         &sky_data,
01677                                         &sky_noise,
01678                                         flux,
01679                                         background,
01680                                         xcal_interpolation));
01681                         } else {     
01682                             /* Lambda correction using OH lines */
01683                             KMO_TRY_EXIT_IF_ERROR(
01684                                     kmo_reconstruct_sci(
01685                                         sky_ifu_nr,
01686                                         bounds[2*(sky_ifu_nr-1)],
01687                                         bounds[2*(sky_ifu_nr-1)+1],
01688                                         sky_as_object_frame,
01689                                         SCIENCE,
01690                                         NULL,
01691                                         NULL,
01692                                         flat_frame,
01693                                         xcal_frame,
01694                                         ycal_frame,
01695                                         lcal_frame,
01696                                         NULL,
01697                                         NULL,
01698                                         &gd,
01699                                         &sky_data,
01700                                         &sky_noise,
01701                                         FALSE,
01702                                         FALSE,
01703                                         xcal_interpolation));
01704                             if (sky_data != NULL) {
01705                                 KMO_TRY_EXIT_IF_NULL(
01706                                     oh_lcorr_coeffs = kmo_lcorr_get(sky_data,
01707                                         header_data[ifu_nr-1],
01708                                         ref_spectrum_frame, gd, filter_id,
01709                                         ifu_nr));
01710                                 cpl_imagelist_delete(sky_data); sky_data = NULL;
01711                                 if (sky_noise != NULL) {
01712                                     cpl_imagelist_delete(sky_noise); 
01713                                     sky_noise = NULL;
01714                                 }
01715                                 KMO_TRY_EXIT_IF_ERROR(
01716                                         kmo_reconstruct_sci(
01717                                             sky_ifu_nr,
01718                                             bounds[2*(sky_ifu_nr-1)],
01719                                             bounds[2*(sky_ifu_nr-1)+1],
01720                                             sky_as_object_frame,
01721                                             SCIENCE,
01722                                             sky_frame,
01723                                             SCIENCE,
01724                                             flat_frame,
01725                                             xcal_frame,
01726                                             ycal_frame,
01727                                             lcal_frame,
01728                                             oh_lcorr_coeffs,
01729                                             velo_corr_ptr,
01730                                             &gd,
01731                                             &sky_data,
01732                                             &sky_noise,
01733                                             flux,
01734                                             background,
01735                                             xcal_interpolation));
01736                                 cpl_polynomial_delete(oh_lcorr_coeffs);
01737                                 oh_lcorr_coeffs = NULL;
01738                             }
01739                         } // end if (ref_spectrum_frame == NULL)
01740 
01741                         if (save_interims && (sky_as_object_frame != NULL)) {
01742                             KMO_TRY_EXIT_IF_NULL(cube_interim_object[ifu_nr-1]=
01743                                     cpl_imagelist_duplicate(cube_data[ifu_nr-1]));
01744                             KMO_TRY_EXIT_IF_NULL(cube_interim_sky[ifu_nr-1]=
01745                                     cpl_imagelist_duplicate(sky_data));
01746                         }
01747 
01748                         cpl_imagelist *tmp_object_cube = cube_data[ifu_nr-1];
01749                         KMO_TRY_EXIT_IF_NULL(cube_data[ifu_nr-1] = 
01750                                 kmo_priv_sky_tweak (tmp_object_cube, sky_data,
01751                                     header_data[ifu_nr-1], .3, tbsub, ifu_nr));
01752                         if (tmp_object_cube != NULL) {
01753                             cpl_imagelist_delete(tmp_object_cube); 
01754                             tmp_object_cube = NULL;
01755                         }
01756                         if (sky_data != NULL) {
01757                             cpl_imagelist_delete(sky_data); sky_data = NULL;
01758                         }
01759                         if (sky_noise != NULL) {
01760                             cpl_imagelist_delete(sky_noise); sky_noise = NULL;
01761                         }
01762                     } // end if (do_sky_subtraction && sky_tweak)
01763 
01764                     /* Maintain flux constant in case the pixscale is diff */
01765                     /* For example, pixscale=0.1 => images 28x28 => scaling=4 */
01766                     KMO_TRY_EXIT_IF_NULL(
01767                         tmpImg = cpl_imagelist_get(cube_data[ifu_nr-1], 0));
01768                     double scaling = (cpl_image_get_size_x(tmpImg)*
01769                             cpl_image_get_size_y(tmpImg)) /
01770                         (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01771                     KMO_TRY_EXIT_IF_ERROR(
01772                         cpl_imagelist_divide_scalar(cube_data[ifu_nr-1], 
01773                             scaling));
01774                     if (cube_noise[ifu_nr-1] != NULL) {
01775                         KMO_TRY_EXIT_IF_ERROR(
01776                             cpl_imagelist_divide_scalar(cube_noise[ifu_nr-1],
01777                                 scaling));
01778                     }
01779 
01780                     if (mapping_mode == NULL) {
01781                         /* Get object name */
01782                         KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s",
01783                                     IFU_NAME_PREFIX, ifu_nr, IFU_NAME_POSTFIX));
01784                         KMO_TRY_EXIT_IF_NULL(tmp_str = cpl_propertylist_get_string(
01785                                     header_data[ifu_nr-1], keyword));
01786                         cpl_free(keyword); keyword = NULL;
01787                     } else {
01788                         tmp_str = mapping_mode;
01789                     }
01790 
01791                     /* Divide cube by telluric correction */
01792                     if (has_telluric) {
01793                         /* Check if the nb of occurences of the object name  */
01794                         /* is the same as the number of found tellurics for */
01795                         /* this object (which can be on different arms) */
01796                         telluric_ok = FALSE;
01797                         for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01798                             if (((strcmp(arm_name_struct->names[jj], tmp_str) == 0) ||
01799                                  (strcmp(arm_name_struct->names[jj], IFUS_USER_DEFINED) == 0)) &&
01800                                 (arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj])) {
01801                                 telluric_ok = TRUE;
01802                                 break;
01803                             }
01804                         }
01805 
01806                         if (telluric_ok) {
01807                             telluric_data = kmo_tweak_load_telluric(frameset,
01808                                     ifu_nr, FALSE, no_subtract);
01809                             KMO_TRY_CHECK_ERROR_STATE();
01810                             if (telluric_data != NULL) {
01811                                 /* Get the index of the telluric noise */
01812                                 index = kmo_identify_index_desc(desc_telluric,
01813                                         ifu_nr, TRUE);
01814                                 KMO_TRY_CHECK_ERROR_STATE();
01815                                 if (desc_telluric.sub_desc[index-1].valid_data 
01816                                         == TRUE) {
01817                                     // load noise if present
01818                                     telluric_noise = kmo_tweak_load_telluric(
01819                                             frameset,ifu_nr, TRUE, no_subtract);
01820                                     KMO_TRY_CHECK_ERROR_STATE();
01821                                 } else {
01822                                     if (print_warning_once_tweak_std_noise && 
01823                                             (cube_noise[ifu_nr-1] != NULL)) {
01824                                         cpl_msg_warning(__func__,"************************************************************");
01825                                         cpl_msg_warning(__func__,"* Noise cubes were calculated, but won't be divided by     *");
01826                                         cpl_msg_warning(__func__,"* telluric error since it is missing.                      *");
01827                                         cpl_msg_warning(__func__,"* In order to get a telluric with errors, execute          *");
01828                                         cpl_msg_warning(__func__,"* kmo_std_star with one of the nearest neighbour methods   *");
01829                                         cpl_msg_warning(__func__,"* (set --imethod to NN, lwNN or swNN)                      *");
01830                                         cpl_msg_warning(__func__,"************************************************************");
01831                                         print_warning_once_tweak_std_noise = 
01832                                             FALSE;
01833                                     }
01834                                 }
01835 
01836                                 KMO_TRY_EXIT_IF_ERROR(kmo_arithmetic_3D_1D(
01837                                             cube_data[ifu_nr-1], telluric_data,
01838                                             cube_noise[ifu_nr-1],
01839                                             telluric_noise, "/"));
01840                             }
01841                         }
01842                     }
01843 
01844                     /* Divide cube by illumination correction */
01845                     if (has_illum_corr) {
01846                         illum_data = kmo_dfs_load_image(frameset, ILLUM_CORR,
01847                                 ifu_nr, FALSE, FALSE, NULL);
01848                         if (cpl_error_get_code() != CPL_ERROR_NONE) {
01849                             cpl_msg_warning(__func__,
01850                             "No illumination correction for IFU %d available! "
01851                                             "Proceeding anyway.", ifu_nr);
01852                             cpl_error_reset();
01853                         } else {
01854                             illum_noise = kmo_dfs_load_image(frameset,
01855                                     ILLUM_CORR, ifu_nr, TRUE, FALSE, NULL);
01856                             if (cpl_error_get_code() != CPL_ERROR_NONE) {
01857                                 cpl_msg_warning(__func__,
01858                             "No illumination correction for IFU %d available! "
01859                                             "Proceeding anyway.", ifu_nr);
01860                                 cpl_image_delete(illum_data); illum_data = NULL;
01861                                 cpl_error_reset();
01862                             }
01863                         }
01864 
01865                         if (illum_data != NULL) {
01866                             KMO_TRY_EXIT_IF_ERROR(
01867                                 kmo_arithmetic_3D_2D(cube_data[ifu_nr-1],
01868                                     illum_data, cube_noise[ifu_nr-1],
01869                                     illum_noise, "/"));
01870                             cpl_image_delete(illum_data); illum_data = NULL;
01871                             cpl_image_delete(illum_noise); illum_noise = NULL;
01872                         }
01873                     }
01874 
01875                     kmclipm_vector_delete(telluric_data); telluric_data = NULL;
01876                     kmclipm_vector_delete(telluric_noise);telluric_noise= NULL;
01877                 } else {
01878                     // IFU is invalid
01879                 }
01880 
01881                 // duplicate subheader data
01882                 KMO_TRY_EXIT_IF_NULL(header_noise[ifu_nr-1] =
01883                         cpl_propertylist_duplicate(header_data[ifu_nr-1]));
01884                 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(ifu_frame,
01885                             ifu_nr, EXT_NOISE));
01886                 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
01887                             header_noise[ifu_nr-1], EXTNAME, extname,
01888                             "FITS extension name"));
01889                 cpl_free(extname); extname = NULL;
01890             } // end for ifu_nr
01891 
01892             /* Count number of reconstructed data- and noise-cubes */
01893             for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
01894                 if (cube_data[ifu_nr-1] != NULL)    cube_counter_data++;
01895                 if (cube_noise[ifu_nr-1] != NULL)   cube_counter_noise++;
01896             }
01897 
01898             /* Save reconstructed cubes of science frame */
01899             if (cube_counter_data > 0) {
01900                 cpl_msg_info(__func__, "   > saving...");
01901 
01902                 if (!suppress_extension) {
01903                     fn_out = fn_obj;
01904 
01905                     int nr_found = 0;
01906                     // remove any path-elements from filename and use it as
01907                     // suffix
01908                     split = kmo_strsplit(fn_out, "/", &nr_found);
01909 
01910                     fn_suffix = cpl_sprintf("_%s", split[nr_found-1]);
01911                     kmo_strfreev(split);
01912 
01913                     // remove '.fits' at the end if there is any
01914                     char *fff = fn_suffix;
01915                     fff += strlen(fn_suffix)-5;
01916                     if (strcmp(fff, ".fits") == 0) {
01917                         fn_suffix[strlen(fn_suffix)-5] = '\0';
01918                     }
01919                 } else {
01920                     KMO_TRY_EXIT_IF_NULL(
01921                         fn_suffix = cpl_sprintf("_%d", suppress_index++));
01922                 }
01923 
01924                 fn_out = RECONSTRUCTED_CUBE;
01925                 fn_interim_object = INTERIM_OBJECT_CUBE;
01926                 fn_interim_sky = INTERIM_OBJECT_SKY;
01927 
01928                 /* Create Primary Header */
01929                 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01930                             fn_out, fn_suffix,
01931                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01932                             NULL, parlist, cpl_func));
01933                 /* save intermediate products (only in sky tweak case) */
01934                 if (save_interims && (sky_as_object_frame != NULL)) {
01935                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01936                                 fn_interim_object, fn_suffix,
01937                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01938                             NULL, parlist, cpl_func));
01939                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01940                                 fn_interim_sky, fn_suffix,
01941                                 arm_name_struct->obj_sky_struct->table[sf].objFrame,
01942                                 NULL, parlist, cpl_func));
01943                 }
01944 
01945                 /* Loop on IFUs */
01946                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01947                     /* Save data Extension */
01948                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(cube_data[ifu_nr-1],
01949                                 fn_out,fn_suffix,header_data[ifu_nr-1], 0./0.));
01950 
01951                     /* Save noise Extension */
01952                     if (cube_counter_noise > 0) {
01953                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01954                                     cube_noise[ifu_nr-1], fn_out, fn_suffix,
01955                                     header_noise[ifu_nr-1], 0./0.));
01956                     }
01957 
01958                     /* save intermediate products (only in sky tweak case */
01959                     if (save_interims && (sky_as_object_frame != NULL)) {
01960                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01961                                     cube_interim_object[ifu_nr-1],
01962                                     fn_interim_object, fn_suffix,
01963                                     header_data[ifu_nr-1], 0./0.));
01964                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01965                                     cube_interim_sky[ifu_nr-1], fn_interim_sky,
01966                                     fn_suffix, header_sky[ifu_nr-1], 0./0.));
01967                     }
01968 
01969                     cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01970                     cube_data[ifu_nr-1] = NULL;
01971                     cpl_imagelist_delete(cube_noise[ifu_nr-1]);
01972                     cube_noise[ifu_nr-1] = NULL;
01973                     cpl_propertylist_delete(header_data[ifu_nr-1]);
01974                     header_data[ifu_nr-1] = NULL;
01975                     cpl_propertylist_delete(header_noise[ifu_nr-1]);
01976                     header_noise[ifu_nr-1] = NULL;
01977                     if (save_interims) {
01978                         cpl_imagelist_delete(cube_interim_object[ifu_nr-1]);
01979                         cube_interim_object[ifu_nr-1] = NULL;
01980                         cpl_imagelist_delete(cube_interim_sky[ifu_nr-1]);
01981                         cube_interim_sky[ifu_nr-1] = NULL;
01982                         cpl_propertylist_delete(header_sky[ifu_nr-1]);
01983                         header_sky[ifu_nr-1] = NULL;
01984                     }
01985                 } // end for ifu_nr
01986                 cpl_free(fn_suffix); fn_suffix = NULL;
01987             } else {
01988                 cpl_msg_info(__func__, "   > all IFUs invalid, don't save");
01989                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01990                     cpl_propertylist_delete(header_data[ifu_nr-1]); 
01991                     header_data[ifu_nr-1] = NULL;
01992                     cpl_propertylist_delete(header_noise[ifu_nr-1]); 
01993                     header_noise[ifu_nr-1] = NULL;
01994                 }
01995             } // if (cube_counter_data > 0) {
01996 
01997             cpl_propertylist_delete(main_header); main_header = NULL;
01998         } // end for sf (arm_name_struct->obj_sky_struct->size)
01999         cpl_free(cube_data);    cube_data = NULL;
02000         cpl_free(cube_noise);    cube_noise = NULL;
02001         cpl_free(header_data);    header_data = NULL;
02002         cpl_free(header_noise);    header_noise = NULL;
02003         if (save_interims) {
02004             cpl_free(cube_interim_object);    cube_interim_object = NULL;
02005             cpl_free(cube_interim_sky);       cube_interim_sky = NULL;
02006             cpl_free(header_sky);             header_sky = NULL;
02007         }
02008 
02009         kmo_print_unused_ifus(unused_ifus_after, TRUE);
02010 
02011         cpl_msg_info("", "-------------------------------------------");
02012 
02013         if (lcal != NULL) {
02014             for (i = 0; i < KMOS_NR_DETECTORS; i++) {
02015                 cpl_image_delete(lcal[i]);
02016             }
02017         }
02018         cpl_free(lcal); lcal = NULL;
02019 
02020         /* Combine */
02021         suppress_index = 0;
02022         if (!no_combine) {
02023             cpl_msg_info(__func__, "Combining reconstructed objects");
02024             nr_reconstructed_frames = cpl_frameset_count_tags(frameset,
02025                     RECONSTRUCTED_CUBE);
02026             if ((mapping_mode == NULL) || ((mapping_mode != NULL) &&
02027                         ((ifus != NULL) || (strcmp(name, "") != 0)))) {
02028                 // loop all available objects
02029                 for (i = 0; i < arm_name_struct->nrNames; i++) {
02030                     cpl_msg_info(__func__, 
02031                             "   > object: %s", arm_name_struct->names[i]);
02032                     nr_data_alloc = arm_name_struct->namesCnt[i];
02033                     KMO_TRY_EXIT_IF_NULL(cube_data=(cpl_imagelist**)cpl_calloc(
02034                                 nr_data_alloc, sizeof(cpl_imagelist*)));
02035                     KMO_TRY_EXIT_IF_NULL(cube_noise=(cpl_imagelist**)cpl_calloc(
02036                                 nr_data_alloc, sizeof(cpl_imagelist*)));
02037                     KMO_TRY_EXIT_IF_NULL(header_data=
02038                             (cpl_propertylist**)cpl_calloc(nr_data_alloc,
02039                                 sizeof(cpl_propertylist*)));
02040                     KMO_TRY_EXIT_IF_NULL(header_noise=
02041                             (cpl_propertylist**)cpl_calloc(nr_data_alloc,
02042                                 sizeof(cpl_propertylist*)));
02043 
02044                     // setup cube-list and header-list for kmo_priv_combine()
02045                     cube_counter_data = 0;
02046                     cube_counter_noise = 0;
02047                     KMO_TRY_EXIT_IF_NULL(tmp_frame = kmo_dfs_get_frame(frameset,
02048                                 RECONSTRUCTED_CUBE));
02049                     while (tmp_frame != NULL ) {
02050                         KMO_TRY_EXIT_IF_NULL(
02051                             fn_reconstr = cpl_frame_get_filename(tmp_frame));
02052                         KMO_TRY_EXIT_IF_NULL(tmp_header = 
02053                                 kmclipm_propertylist_load(fn_reconstr, 0));
02054                         kmo_free_fits_desc(&desc1);
02055                         kmo_init_fits_desc(&desc1);
02056                         desc1 = kmo_identify_fits_header(fn_reconstr);
02057 
02058                         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
02059                             // check if object-name equals the one in our list
02060                             KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s",
02061                                         IFU_NAME_PREFIX, ifu_nr, 
02062                                         IFU_NAME_POSTFIX));
02063                             KMO_TRY_EXIT_IF_NULL(tmp_str = 
02064                                     cpl_propertylist_get_string(tmp_header,
02065                                         keyword));
02066                             cpl_free(keyword); keyword = NULL;
02067 
02068                             if ((strcmp(arm_name_struct->names[i],tmp_str)==0)
02069                                     || (strcmp(arm_name_struct->names[i],
02070                                             IFUS_USER_DEFINED) == 0)) {
02071                                 // found object-IFU with matching name
02072                                 // load data & subheader
02073                                 index = kmo_identify_index(fn_reconstr, ifu_nr,
02074                                         FALSE);
02075                                 KMO_TRY_CHECK_ERROR_STATE();
02076 
02077                                 if (desc1.sub_desc[index-1].valid_data) {
02078                                     KMO_TRY_EXIT_IF_NULL(
02079                                         cube_data[cube_counter_data] =
02080                                             kmclipm_imagelist_load(fn_reconstr,
02081                                                 CPL_TYPE_FLOAT, index));
02082         /* Set cubes borders (1 pixel) to Nan to avoid jumps in combined cube */
02083                                     if (edge_nan) {
02084                                         KMO_TRY_EXIT_IF_ERROR(kmo_edge_nan(
02085                                                     cube_data[cube_counter_data], 
02086                                                     ifu_nr));
02087                                     }
02088 
02089                                     KMO_TRY_EXIT_IF_NULL(
02090                                         header_data[cube_counter_data] =
02091                                             kmclipm_propertylist_load(
02092                                                 fn_reconstr, index));
02093                                     cpl_propertylist_update_string(
02094                                             header_data[cube_counter_data],
02095                                             "ESO PRO FRNAME", fn_reconstr);
02096                                     cpl_propertylist_update_int(
02097                                             header_data[cube_counter_data],
02098                                             "ESO PRO IFUNR", ifu_nr);
02099                                     cube_counter_data++;
02100                                 }
02101 
02102                                 // load noise & subheader (if existing)
02103                                 if (desc1.ex_noise) {
02104                                     index = kmo_identify_index(fn_reconstr,
02105                                             ifu_nr, TRUE);
02106                                     KMO_TRY_CHECK_ERROR_STATE();
02107 
02108                                     if (desc1.sub_desc[index-1].valid_data) {
02109                                         KMO_TRY_EXIT_IF_NULL(
02110                                             cube_noise[cube_counter_noise] =
02111                                                 kmclipm_imagelist_load(
02112                                                     fn_reconstr, CPL_TYPE_FLOAT,
02113                                                     index));
02114                                         if (edge_nan) {
02115                                             KMO_TRY_EXIT_IF_ERROR(
02116                                                 kmo_edge_nan(cube_noise[cube_counter_noise], ifu_nr));
02117                                         }
02118                                         KMO_TRY_EXIT_IF_NULL(
02119                                             header_noise[cube_counter_noise] =
02120                                                 kmclipm_propertylist_load(
02121                                                     fn_reconstr, index));
02122                                         cube_counter_noise++;
02123                                     }
02124                                 }
02125                                 cpl_error_reset();
02126                             } // end if found obj
02127                         } // end for ifu_nr
02128 
02129                         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02130                         tmp_frame = kmo_dfs_get_frame(frameset, NULL);
02131                         KMO_TRY_CHECK_ERROR_STATE();
02132                     } // end while-loop RECONSTRUCTED_CUBE frames
02133 
02134                     if (cube_counter_data > 1) {
02135                         if (cube_counter_data == cube_counter_noise) {
02136                             KMO_TRY_EXIT_IF_ERROR(
02137                                 kmo_priv_combine(cube_data,
02138                                     cube_noise,
02139                                     header_data,
02140                                     header_noise,
02141                                     cube_counter_data,
02142                                     cube_counter_noise,
02143                                     arm_name_struct->names[i],
02144                                     "",
02145                                     comb_method,
02146                                     smethod,
02147                                     fmethod,
02148                                     filename,
02149                                     cmethod,
02150                                     cpos_rej,
02151                                     cneg_rej,
02152                                     citer,
02153                                     cmin,
02154                                     cmax,
02155                                     extrapol_enum,
02156                                     flux,
02157                                     &combined_data,
02158                                     &combined_noise,
02159                                     &exp_mask));
02160                         } else if (cube_counter_noise == 0) {
02161                             KMO_TRY_EXIT_IF_ERROR(
02162                                 kmo_priv_combine(cube_data,
02163                                     NULL,
02164                                     header_data,
02165                                     header_noise,
02166                                     cube_counter_data,
02167                                     cube_counter_noise,
02168                                     arm_name_struct->names[i],
02169                                     "",
02170                                     comb_method,
02171                                     smethod,
02172                                     fmethod,
02173                                     filename,
02174                                     cmethod,
02175                                     cpos_rej,
02176                                     cneg_rej,
02177                                     citer,
02178                                     cmin,
02179                                     cmax,
02180                                     extrapol_enum,
02181                                     flux,
02182                                     &combined_data,
02183                                     &combined_noise,
02184                                     &exp_mask));
02185                         } else {
02186                             KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
02187                                     "The number of cube-data and cube-noise "
02188                                     "isn't the same (%d vs. %d)!",
02189                                     cube_counter_data, cube_counter_noise);
02190                         }
02191                     } else if (cube_counter_data == 1) {
02192                         cpl_msg_warning(__func__, 
02193                                 "There is only one reconstructed cube with "
02194                                 "this object! Saving it as it is.");
02195                         KMO_TRY_EXIT_IF_NULL(combined_data = 
02196                                 cpl_imagelist_duplicate(cube_data[0]));
02197                         KMO_TRY_EXIT_IF_NULL(tmpImg = 
02198                                 cpl_imagelist_get(combined_data, 0));
02199                         KMO_TRY_EXIT_IF_NULL(exp_mask = cpl_image_new(
02200                                     cpl_image_get_size_x(tmpImg),
02201                                     cpl_image_get_size_y(tmpImg), 
02202                                     CPL_TYPE_FLOAT));
02203                         KMO_TRY_EXIT_IF_ERROR(kmo_image_fill(exp_mask, 1.));
02204 
02205                         if (cube_noise[0] != NULL) {
02206                             KMO_TRY_EXIT_IF_NULL(
02207                                 combined_noise = cpl_imagelist_duplicate(
02208                                     cube_noise[0]));
02209                         }
02210                     } else {
02211                         KMO_TRY_ASSURE(1==0, CPL_ERROR_ILLEGAL_INPUT,
02212                                 "No cubes found with this object name!");
02213                     } // end if (cube_counter_data > 1)
02214 
02215                     fn_out = COMBINED_CUBE;
02216                     fn_out_mask = EXP_MASK;
02217                     if (!suppress_extension) {
02218                         char tmp_suffix[1024];
02219                         tmp_suffix[0] = '\0';
02220 
02221                         if (arm_name_struct->telluricCnt[i] == 
02222                                 arm_name_struct->namesCnt[i]) {
02223                             strcat(tmp_suffix, "_telluric");
02224                         }
02225                         if (has_illum_corr)     strcat(tmp_suffix, "_illum");
02226                         if (sky_tweak)          strcat(tmp_suffix, "_skytweak");
02227 
02228                         if (strlen(tmp_suffix) > 0) {
02229                             KMO_TRY_EXIT_IF_NULL(
02230                                 fn_suffix = cpl_sprintf("_%s_%s", 
02231                                     arm_name_struct->names[i], tmp_suffix));
02232                         } else {
02233                             KMO_TRY_EXIT_IF_NULL(
02234                                 fn_suffix = cpl_sprintf("_%s", 
02235                                     arm_name_struct->names[i]));
02236                         }
02237                     } else {
02238                         KMO_TRY_EXIT_IF_NULL(
02239                             fn_suffix = cpl_sprintf("_%d", suppress_index++));
02240                     }
02241 
02242                     // save combined cube
02243                     KMO_TRY_EXIT_IF_NULL(tmp_frame = 
02244                             kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE));
02245                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
02246                                 fn_out, fn_suffix, tmp_frame, NULL, parlist, 
02247                                 cpl_func));
02248                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
02249                                 fn_out_mask, fn_suffix, tmp_frame, NULL, 
02250                                 parlist, cpl_func));
02251                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(combined_data, 
02252                                 fn_out, fn_suffix, header_data[0], 0./0.));
02253                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(exp_mask, 
02254                                 fn_out_mask, fn_suffix, header_data[0], 0./0.));
02255                         
02256                     if (header_noise[0] == NULL) {
02257                         KMO_TRY_EXIT_IF_NULL(header_noise[0] = 
02258                                 cpl_propertylist_duplicate(header_data[0]));
02259 
02260                         KMO_TRY_EXIT_IF_NULL(tmp_str = 
02261                                 cpl_propertylist_get_string(header_data[0], 
02262                                     EXTNAME));
02263                         KMO_TRY_EXIT_IF_ERROR(kmo_extname_extractor(tmp_str, 
02264                                     &ft, &tmp_int, content));
02265                         KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(
02266                                     ifu_frame, tmp_int, EXT_NOISE));
02267                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
02268                                     header_noise[0], EXTNAME, extname,
02269                                     "FITS extension name"));
02270                         cpl_free(extname); extname = NULL;
02271                     }
02272                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(combined_noise, 
02273                                 fn_out, fn_suffix, header_noise[0], 0./0.));
02274 
02275                     for (jj = 0; jj < nr_data_alloc; jj++) {
02276                         cpl_imagelist_delete(cube_data[jj]); 
02277                         cube_data[jj] = NULL;
02278                         cpl_imagelist_delete(cube_noise[jj]); 
02279                         cube_noise[jj] = NULL;
02280                         cpl_propertylist_delete(header_data[jj]); 
02281                         header_data[jj] = NULL;
02282                         cpl_propertylist_delete(header_noise[jj]); 
02283                         header_noise[jj] = NULL;
02284                     }
02285                     cpl_free(cube_data);    cube_data = NULL;
02286                     cpl_free(cube_noise);   cube_noise = NULL;
02287                     cpl_free(header_data);  header_data = NULL;
02288                     cpl_free(header_noise); header_noise = NULL;
02289                     cpl_free(fn_suffix); fn_suffix = NULL;
02290                     cpl_imagelist_delete(combined_data); combined_data = NULL;
02291                     cpl_imagelist_delete(combined_noise); combined_noise = NULL;
02292                     cpl_image_delete(exp_mask); exp_mask = NULL;
02293                 } // for i = nr_avail_obj_names
02294             } else {
02295                 // we are in mapping_mode
02296                 nr_data_alloc = nr_reconstructed_frames*KMOS_NR_IFUS;
02297                 KMO_TRY_EXIT_IF_NULL(cube_data = (cpl_imagelist**)cpl_calloc(
02298                             nr_data_alloc, sizeof(cpl_imagelist*)));
02299                 KMO_TRY_EXIT_IF_NULL(cube_noise = (cpl_imagelist**)cpl_calloc(
02300                             nr_data_alloc, sizeof(cpl_imagelist*)));
02301                 KMO_TRY_EXIT_IF_NULL(header_data=(cpl_propertylist**)cpl_calloc(
02302                             nr_data_alloc, sizeof(cpl_propertylist*)));
02303                 KMO_TRY_EXIT_IF_NULL(header_noise=(cpl_propertylist**)cpl_calloc(
02304                             nr_data_alloc, sizeof(cpl_propertylist*)));
02305 
02306                 cube_counter_data = 0;
02307                 cube_counter_noise = 0;
02308                 KMO_TRY_EXIT_IF_NULL(tmp_frame = 
02309                         kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE));
02310                 while (tmp_frame != NULL ) {
02311                     KMO_TRY_EXIT_IF_NULL(
02312                         fn_reconstr = cpl_frame_get_filename(tmp_frame));
02313                     KMO_TRY_EXIT_IF_NULL(
02314                         tmp_header = kmclipm_propertylist_load(fn_reconstr, 0));
02315 
02316                     kmo_free_fits_desc(&desc1);
02317                     kmo_init_fits_desc(&desc1);
02318                     desc1 = kmo_identify_fits_header(fn_reconstr);
02319                     for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
02320                         index = kmo_identify_index(fn_reconstr, ifu_nr, FALSE);
02321                         KMO_TRY_CHECK_ERROR_STATE();
02322 
02323                         if (desc1.sub_desc[index-1].valid_data) {
02324                             KMO_TRY_EXIT_IF_NULL(cube_data[cube_counter_data] =
02325                                     kmclipm_imagelist_load(fn_reconstr, 
02326                                         CPL_TYPE_FLOAT, index));
02327                             if (edge_nan) {
02328                                 KMO_TRY_EXIT_IF_ERROR(
02329                                     kmo_edge_nan(cube_data[cube_counter_data], 
02330                                         ifu_nr));
02331                             }
02332 
02333                             if (fast_mode) {
02334                                 KMO_TRY_EXIT_IF_NULL(tmpImg = 
02335                                         cpl_imagelist_collapse_median_create(
02336                                             cube_data[cube_counter_data]));
02337                                 KMO_TRY_EXIT_IF_NULL(
02338                                     tmpCube = cpl_imagelist_new());
02339                                 KMO_TRY_EXIT_IF_ERROR(
02340                                     cpl_imagelist_set(tmpCube, tmpImg, 0));
02341                                 cpl_imagelist_delete(cube_data[cube_counter_data]);
02342                                 cube_data[cube_counter_data] = tmpCube;
02343                             }
02344 
02345                             KMO_TRY_EXIT_IF_NULL(
02346                                 header_data[cube_counter_data] =
02347                                     kmclipm_propertylist_load(fn_reconstr, index));
02348                             cpl_propertylist_update_string(
02349                                     header_data[cube_counter_data], 
02350                                     "ESO PRO FRNAME", fn_reconstr);
02351                             cpl_propertylist_update_int(
02352                                     header_data[cube_counter_data], 
02353                                     "ESO PRO IFUNR", ifu_nr);
02354                             cube_counter_data++;
02355                         }
02356 
02357                         // load noise & subheader (if existing)
02358                         if (desc1.ex_noise) {
02359                             index = kmo_identify_index(fn_reconstr,ifu_nr,TRUE);
02360                             KMO_TRY_CHECK_ERROR_STATE();
02361                             if (desc1.sub_desc[index-1].valid_data) {
02362                                 KMO_TRY_EXIT_IF_NULL(
02363                                     cube_noise[cube_counter_noise] =
02364                                         kmclipm_imagelist_load(fn_reconstr, 
02365                                             CPL_TYPE_FLOAT, index));
02366 
02367                                 if (edge_nan) {
02368                                     KMO_TRY_EXIT_IF_ERROR(kmo_edge_nan(
02369                                                 cube_noise[cube_counter_noise],
02370                                                 ifu_nr));
02371                                 }
02372 
02373                                 if (fast_mode) {
02374                                     KMO_TRY_EXIT_IF_NULL(tmpImg = 
02375                                             cpl_imagelist_collapse_median_create(cube_noise[cube_counter_noise]));
02376                                     KMO_TRY_EXIT_IF_NULL(
02377                                         tmpCube = cpl_imagelist_new());
02378                                     KMO_TRY_EXIT_IF_ERROR(
02379                                         cpl_imagelist_set(tmpCube, tmpImg, 0));
02380                                     cpl_imagelist_delete(cube_noise[cube_counter_noise]);
02381                                     cube_noise[cube_counter_noise] = tmpCube;
02382                                 }
02383                                 KMO_TRY_EXIT_IF_NULL(
02384                                     header_noise[cube_counter_noise] = 
02385                                     kmclipm_propertylist_load(fn_reconstr,
02386                                         index));
02387                                 cube_counter_noise++;
02388                             }
02389                         }
02390                         cpl_error_reset();
02391                     } // end for ifu_nr
02392 
02393                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02394                     tmp_frame = kmo_dfs_get_frame(frameset, NULL);
02395                     KMO_TRY_CHECK_ERROR_STATE();
02396                 } // end while-loop RECONSTRUCTED_CUBE frames
02397 
02398                 if (cube_counter_data > 1) {
02399                     if (cube_counter_data == cube_counter_noise) {
02400                         KMO_TRY_EXIT_IF_ERROR(
02401                             kmo_priv_combine(cube_data,
02402                                 cube_noise,
02403                                 header_data,
02404                                 header_noise,
02405                                 cube_counter_data,
02406                                 cube_counter_noise,
02407                                 mapping_mode,
02408                                 "",
02409                                 comb_method,
02410                                 smethod,
02411                                 fmethod,
02412                                 filename,
02413                                 cmethod,
02414                                 cpos_rej,
02415                                 cneg_rej,
02416                                 citer,
02417                                 cmin,
02418                                 cmax,
02419                                 extrapol_enum,
02420                                 flux,
02421                                 &combined_data,
02422                                 &combined_noise,
02423                                 NULL));
02424                     } else if (cube_counter_noise == 0) {
02425                         KMO_TRY_EXIT_IF_ERROR(
02426                             kmo_priv_combine(cube_data,
02427                                 NULL,
02428                                 header_data,
02429                                 header_noise,
02430                                 cube_counter_data,
02431                                 cube_counter_noise,
02432                                 mapping_mode,
02433                                 "",
02434                                 comb_method,
02435                                 smethod,
02436                                 fmethod,
02437                                 filename,
02438                                 cmethod,
02439                                 cpos_rej,
02440                                 cneg_rej,
02441                                 citer,
02442                                 cmin,
02443                                 cmax,
02444                                 extrapol_enum,
02445                                 flux,
02446                                 &combined_data,
02447                                 &combined_noise,
02448                                 NULL));
02449                     } else {
02450                         KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
02451                                 "The number of cube-data and cube-noise "
02452                                 "isn't the same (%d vs. %d)!",
02453                                 cube_counter_data, cube_counter_noise);
02454                     }
02455                 } else {
02456                     cpl_msg_warning(__func__, 
02457                             "There is only one reconstructed cube - Save it");
02458                     KMO_TRY_EXIT_IF_NULL(
02459                         combined_data = cpl_imagelist_duplicate(cube_data[0]));
02460 
02461                     if (cube_noise[0] != NULL) {
02462                         KMO_TRY_EXIT_IF_NULL(
02463                             combined_noise = cpl_imagelist_duplicate(
02464                                 cube_noise[0]));
02465                     }
02466                 }
02467 
02468                 fn_out = COMBINED_CUBE;
02469                 KMO_TRY_EXIT_IF_NULL(
02470                     fn_suffix = cpl_sprintf("_%s", mapping_mode));
02471 
02472                 // save combined cube
02473                 KMO_TRY_EXIT_IF_NULL(tmp_frame = kmo_dfs_get_frame(frameset,
02474                             RECONSTRUCTED_CUBE));
02475                 KMO_TRY_EXIT_IF_ERROR(
02476                     kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, 
02477                         tmp_frame, NULL, parlist, cpl_func));
02478 
02479                 KMO_TRY_EXIT_IF_ERROR(
02480                     kmo_dfs_save_cube(combined_data, fn_out, fn_suffix,
02481                         header_data[0], 0./0.));
02482 
02483                 if (header_noise[0] == NULL) {
02484                     KMO_TRY_EXIT_IF_NULL(
02485                         header_noise[0] =
02486                              cpl_propertylist_duplicate(header_data[0]));
02487 
02488                     KMO_TRY_EXIT_IF_NULL(
02489                         tmp_str = cpl_propertylist_get_string(header_data[0],
02490                             EXTNAME));
02491                     KMO_TRY_EXIT_IF_ERROR(
02492                         kmo_extname_extractor(tmp_str, &ft, &tmp_int, content));
02493                     KMO_TRY_EXIT_IF_NULL(
02494                         extname = kmo_extname_creator(ifu_frame, tmp_int,
02495                             EXT_NOISE));
02496                     KMO_TRY_EXIT_IF_ERROR(
02497                         kmclipm_update_property_string(header_noise[0], EXTNAME,
02498                             extname, "FITS extension name"));
02499                     cpl_free(extname); extname = NULL;
02500                 }
02501                 KMO_TRY_EXIT_IF_ERROR(
02502                     kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix,
02503                         header_noise[0], 0./0.));
02504 
02505                 for (i = 0; i < nr_data_alloc; i++) {
02506                     cpl_imagelist_delete(cube_data[i]); cube_data[i] = NULL;
02507                     cpl_imagelist_delete(cube_noise[i]); cube_noise[i] = NULL;
02508                     cpl_propertylist_delete(header_data[i]); 
02509                     header_data[i] = NULL;
02510                     cpl_propertylist_delete(header_noise[i]); 
02511                     header_noise[i] = NULL;
02512                 }
02513                 cpl_free(cube_data);    cube_data = NULL;
02514                 cpl_free(cube_noise);   cube_noise = NULL;
02515                 cpl_free(header_data);  header_data = NULL;
02516                 cpl_free(header_noise); header_noise = NULL;
02517                 cpl_free(fn_suffix); fn_suffix = NULL;
02518                 cpl_imagelist_delete(combined_data); combined_data = NULL;
02519                 cpl_imagelist_delete(combined_noise); combined_noise = NULL;
02520             } // if mapping_mode
02521         } else {
02522             cpl_msg_info("", "Reconstructed objects are not combined");
02523         } // if (!no_combine)
02524         cpl_msg_info("", "-------------------------------------------");
02525     }
02526     KMO_CATCH
02527     {
02528         KMO_CATCH_MSG();
02529         ret_val = -1;
02530     }
02531     if (cube_data != NULL) {
02532         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02533             cpl_imagelist_delete(cube_data[ifu_nr-1]); 
02534             cube_data[ifu_nr-1] = NULL;
02535         }
02536     }
02537     cpl_free(cube_data);    cube_data = NULL;
02538     if (cube_noise != NULL) {
02539         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02540             cpl_imagelist_delete(cube_noise[ifu_nr-1]); 
02541             cube_noise[ifu_nr-1] = NULL;
02542         }
02543     }
02544     cpl_free(cube_noise);   cube_noise = NULL;
02545     if (header_data != NULL) {
02546         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02547             cpl_propertylist_delete(header_data[ifu_nr-1]);
02548             header_data[ifu_nr-1] = NULL;
02549         }
02550     }
02551     cpl_free(header_data);  header_data = NULL;
02552     if (header_noise != NULL) {
02553         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02554             cpl_propertylist_delete(header_noise[ifu_nr-1]);
02555             header_noise[ifu_nr-1] = NULL;
02556         }
02557     }
02558     cpl_free(header_noise); header_noise = NULL;
02559 
02560 
02561     kmo_free_fits_desc(&desc1);
02562     kmo_free_fits_desc(&desc2);
02563     kmo_free_fits_desc(&desc_telluric);
02564 
02565     cpl_vector_delete(ifus); ifus = NULL;
02566     cpl_free(mapping_mode); mapping_mode = NULL;
02567     if (unused_ifus_before != NULL) {
02568         kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL;
02569     }
02570     if (unused_ifus_after != NULL) {
02571         kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL;
02572     }
02573     if (bounds != NULL) {
02574         cpl_free(bounds); bounds = NULL;
02575     }
02576 
02577     // frees for the case of errors
02578     kmclipm_vector_delete(telluric_data); telluric_data = NULL;
02579     kmclipm_vector_delete(telluric_noise); telluric_noise = NULL;
02580     cpl_image_delete(illum_data); illum_data = NULL;
02581     cpl_image_delete(illum_noise); illum_noise = NULL;
02582     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02583     cpl_table_delete(band_table); band_table = NULL;
02584     cpl_propertylist_delete(main_header); main_header = NULL;
02585     if (lcal != NULL) {
02586         for (i = 0; i < KMOS_NR_DETECTORS; i++) {
02587             cpl_image_delete(lcal[i]);
02588         }
02589     }
02590     cpl_free(lcal); lcal = NULL;
02591     cpl_free(fn_suffix); fn_suffix = NULL;
02592     cpl_free(suffix); suffix = NULL;
02593 
02594     kmo_delete_armNameStruct(arm_name_struct);
02595 
02596     return ret_val;
02597 }
02598