KMOS Pipeline Reference Manual  1.3.0
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     kmo_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 kmo_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         kmo_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             kmo_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 
01298                             KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT," ");
01299                         }
01300                     }
01301                 }
01302             }
01303 
01304             KMO_TRY_EXIT_IF_NULL(
01305                 arm_name_struct = kmo_create_armNameStruct2(obj_sky_struct,
01306                     frameset, SCIENCE, ifus, name, unused_ifus_after, bounds,
01307                     mapping_mode, no_subtract));
01308         }
01309         kmo_print_armNameStruct(frameset, arm_name_struct);
01310 
01311         /* Check Telluric availability for each Object */
01312         /* Why only mapping  ? Not clear */
01313         /* in mapping-mode check if for all IFUs there is either no  */
01314         /* telluric at all or the same number of tellurics than object names */
01315         if ((has_telluric) && (mapping_mode != NULL)) {
01316             telluric_ok = TRUE;
01317             for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01318                 if (!((arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj]) ||
01319                     (arm_name_struct->telluricCnt[jj] == 0))) {
01320                     telluric_ok = FALSE;
01321                     break;
01322                 }
01323             }
01324             if (!telluric_ok) {
01325                 KMO_TRY_ASSURE(1==0, CPL_ERROR_UNSUPPORTED_MODE,
01326                         "Mosaics need a TELLURIC frame with at least a telluric correction per detector available! "
01327                         "Omit the TELLURIC from your sof-file or choose another TELLURIC!");
01328             }
01329         }
01330 
01331         /* Load lcal-frames */
01332         KMO_TRY_EXIT_IF_NULL(lcal = (cpl_image**)cpl_calloc(KMOS_NR_DETECTORS, 
01333                     sizeof(cpl_image*)));
01334         for (i = 0; i < KMOS_NR_DETECTORS; i++) {
01335             KMO_TRY_EXIT_IF_NULL(lcal[i] = kmo_dfs_load_image(frameset, LCAL, 
01336                         i+1, FALSE, FALSE, NULL));
01337         }
01338 
01339         nr_data_alloc = KMOS_NR_IFUS;
01340         KMO_TRY_EXIT_IF_NULL(cube_data = (cpl_imagelist**)cpl_calloc(
01341                     nr_data_alloc, sizeof(cpl_imagelist*)));
01342         KMO_TRY_EXIT_IF_NULL(cube_noise = (cpl_imagelist**)cpl_calloc(
01343                     nr_data_alloc, sizeof(cpl_imagelist*)));
01344         KMO_TRY_EXIT_IF_NULL(header_data = (cpl_propertylist**)cpl_calloc(
01345                     nr_data_alloc, sizeof(cpl_propertylist*)));
01346         KMO_TRY_EXIT_IF_NULL(header_noise = (cpl_propertylist**)cpl_calloc(
01347                     nr_data_alloc, sizeof(cpl_propertylist*)));
01348 
01349         if (save_interims) {
01350             KMO_TRY_EXIT_IF_NULL(cube_interim_object=(cpl_imagelist**)cpl_calloc(
01351                         nr_data_alloc, sizeof(cpl_imagelist*)));
01352             KMO_TRY_EXIT_IF_NULL(cube_interim_sky =(cpl_imagelist**)cpl_calloc(
01353                         nr_data_alloc, sizeof(cpl_imagelist*)));
01354             KMO_TRY_EXIT_IF_NULL(header_sky = (cpl_propertylist**)cpl_calloc(
01355                         nr_data_alloc, sizeof(cpl_propertylist*)));
01356         }
01357 
01358         if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
01359             no_combine = TRUE;
01360             cpl_msg_info(__func__, 
01361                     "--no_combine set to TRUE since there is 1 SCIENCE frame");
01362         }
01363 
01364         if (no_subtract) {
01365             no_combine = TRUE;
01366             cpl_msg_info(__func__, 
01367                     "--no_combine set to TRUE since --no_subtract is set");
01368         }
01369         actual_msg_level = cpl_msg_get_level();
01370         cpl_msg_info("", "-------------------------------------------");
01371 
01372         /* Check if input SCIENCE frames are really ALL observations */
01373         /* If not, Omit the OH_SPEC, even if it is passed - issue a Warning */
01374         if (has_oh_spec) {
01375             int is_all_obs          = TRUE,
01376                 has_all_origfile    = TRUE;
01377 
01378             KMO_TRY_EXIT_IF_NULL(
01379                 tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
01380             while (tmp_frame != NULL ) {
01381                 KMO_TRY_EXIT_IF_NULL(tmp_header = kmclipm_propertylist_load(
01382                             cpl_frame_get_filename(tmp_frame), 0));
01383                 if (cpl_propertylist_has(tmp_header, ORIGFILE)) {
01384                     KMO_TRY_EXIT_IF_NULL(tmp_str = 
01385                             cpl_propertylist_get_string(tmp_header, ORIGFILE));
01386                     if (strstr(tmp_str, "OBS") == NULL) {
01387                         is_all_obs = FALSE;
01388                     }
01389                 } else {
01390                     has_all_origfile = FALSE;
01391                 }
01392                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01393                 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01394                 KMO_TRY_CHECK_ERROR_STATE();
01395             }
01396 
01397             if (has_all_origfile) {
01398                 if (is_all_obs) {
01399                     /* OBS-frame reconstruction - allow OH_SPEC */
01400                     KMO_TRY_EXIT_IF_NULL(ref_spectrum_frame = 
01401                             kmo_dfs_get_frame(frameset, OH_SPEC));
01402 
01403                     /* Verify OH_SPEC */
01404                     /* TODO */
01405 
01406                 } else {
01407                     cpl_msg_warning(__func__, 
01408                             "Supplied OH_SPEC is ignored since a calibration "
01409                             "frame is being used as SCIENCE frame.");
01410                 }
01411             } else {
01412                 cpl_msg_warning(__func__, 
01413                         "Supplied OH_SPEC is ignored since a calibration "
01414                         "frame is being used as SCIENCE frame.");
01415             }
01416         }
01417 
01418         /* Loop all science frames containing at least one object */
01419         cpl_msg_info(__func__, "Reconstructing & saving cubes with objects");
01420         for (sf = 0; sf < arm_name_struct->size; sf++) {
01421             KMO_TRY_EXIT_IF_NULL(fn_obj = cpl_frame_get_filename(
01422                         arm_name_struct->obj_sky_struct->table[sf].objFrame));
01423             KMO_TRY_EXIT_IF_NULL(
01424                 main_header = kmclipm_propertylist_load(fn_obj, 0));
01425             actual_msg_level = cpl_msg_get_level();
01426 
01427             /* Reconstruct science frame */
01428             cpl_msg_info(__func__, "   > processing frame: %s", fn_obj);
01429             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01430                 sky_ifu_nr = ifu_nr;
01431                 det_nr = (ifu_nr - 1)/KMOS_IFUS_PER_DETECTOR + 1;
01432 
01433                 KMO_TRY_ASSURE((det_nr >= 1) && (det_nr <= KMOS_NR_DETECTORS),
01434                         CPL_ERROR_ILLEGAL_INPUT,
01435                         "The provided ifu-numbers are incorrect! They "
01436                         "must be between 1 and %d", KMOS_NR_IFUS);
01437 
01438                 /* Get subheader data */
01439                 KMO_TRY_EXIT_IF_NULL(header_data[ifu_nr-1] = 
01440                         kmclipm_propertylist_load(fn_obj, det_nr));
01441                 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(ifu_frame, 
01442                             ifu_nr, EXT_DATA));
01443                 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
01444                             header_data[ifu_nr-1], EXTNAME, extname,
01445                             "FITS extension name"));
01446                 cpl_free(extname); extname = NULL;
01447 
01448                 if (arm_name_struct->name_ids[ifu_nr-1+sf*KMOS_NR_IFUS] >= 1) {
01449                     // IFU is valid
01450 
01451                     /* Fill do_sky_subtraction and sky_frame */
01452                     if ((arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1] != NO_CORRESPONDING_SKYFRAME) && !no_subtract) {
01453                         do_sky_subtraction = TRUE;
01454                         if (no_subtract) {
01455                             sky_frame = NULL;
01456                         } else {
01457                             sky_frame = arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1];
01458                             KMO_TRY_EXIT_IF_NULL(
01459                                 fn_sky = cpl_frame_get_filename(sky_frame));
01460                         }
01461 
01462                         if (sky_tweak){
01463                             sky_as_object_frame = sky_frame;
01464                             sky_frame = NULL;
01465                             sky_ifu_nr = arm_name_struct->obj_sky_struct->table[sf].skyIfus[ifu_nr-1];
01466                         }
01467 
01468                         if (no_subtract) {
01469                             cpl_msg_warning(__func__, 
01470                                     "      > Omit sky subtraction on IFU %d", 
01471                                     ifu_nr);
01472                         } else {
01473                             if (sky_ifu_nr == ifu_nr) {
01474                                 cpl_msg_info(__func__, 
01475                                         "      > IFU %d (sky in frame: %s)",
01476                                         ifu_nr, fn_sky);
01477                             } else {
01478                                 cpl_msg_info(__func__, 
01479                                         "      > IFU %d (sky in IFU %d of frame: %s)",
01480                                         ifu_nr, sky_ifu_nr, fn_sky);
01481                             }
01482                         }
01483                     } else {
01484                         do_sky_subtraction = FALSE;
01485                         sky_frame = NULL;
01486                         if (!no_subtract) {
01487                             cpl_msg_warning(__func__, 
01488                                     "      > IFU %d with no corresponding sky frame", 
01489                                     ifu_nr);
01490                         }
01491                     }
01492 
01493                     /* Get filter for this detector and setup grid definition using WAVE_BAND */
01494                     KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s", 
01495                                 IFU_FILTID_PREFIX, det_nr, IFU_FILTID_POSTFIX));
01496                     KMO_TRY_EXIT_IF_NULL(filter_id = 
01497                             cpl_propertylist_get_string(main_header, keyword));
01498                     cpl_free(keyword); keyword = NULL;
01499 
01500                     /* TODO : Review print_once mechanism */
01501                     /* Used to print once per detector - problematic for parallelisation */
01502                     if (print_once)     cpl_msg_set_level(CPL_MSG_WARNING);
01503 
01504                     KMO_TRY_EXIT_IF_NULL(band_table = kmo_dfs_load_table(
01505                                 frameset, WAVE_BAND, 1, 0));
01506                     KMO_TRY_EXIT_IF_ERROR(kmclipm_setup_grid_band_lcal(&gd, 
01507                                 filter_id, band_table));
01508                     cpl_table_delete(band_table); band_table = NULL;
01509 
01510                     print_once = TRUE;
01511                     cpl_msg_set_level(actual_msg_level);
01512 
01513                     /* calc WCS & update subheader */
01514                     KMO_TRY_EXIT_IF_ERROR(kmo_calc_wcs_gd(main_header, 
01515                                 header_data[ifu_nr-1], ifu_nr, gd));
01516 
01517                     /* Update some keywords  */
01518                     KMO_TRY_EXIT_IF_ERROR(
01519                         kmclipm_update_property_int(header_data[ifu_nr-1],
01520                             NAXIS, 3, "number of data axes"));
01521                     KMO_TRY_EXIT_IF_ERROR(
01522                         kmclipm_update_property_int(header_data[ifu_nr-1],
01523                             NAXIS1, gd.x.dim, "length of data axis 1"));
01524                     KMO_TRY_EXIT_IF_ERROR(
01525                         kmclipm_update_property_int(header_data[ifu_nr-1],
01526                             NAXIS2, gd.y.dim, "length of data axis 2"));
01527                     KMO_TRY_EXIT_IF_ERROR(
01528                         kmclipm_update_property_int(header_data[ifu_nr-1],
01529                             NAXIS3, gd.l.dim, "length of data axis 3"));
01530 
01531                     /* Option save_interim only applies if sky_tweak is used */
01532                     if (save_interims && (sky_as_object_frame != NULL)) {
01533                         KMO_TRY_EXIT_IF_NULL(
01534                                 main_sky_header = kmclipm_propertylist_load(
01535                                         cpl_frame_get_filename(
01536                                             sky_as_object_frame), 0));
01537                         KMO_TRY_EXIT_IF_NULL(
01538                                 header_sky[ifu_nr-1]=kmclipm_propertylist_load(
01539                                     cpl_frame_get_filename(
01540                                         sky_as_object_frame), det_nr));
01541                         KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(
01542                                     ifu_frame, ifu_nr, EXT_DATA));
01543                         KMO_TRY_EXIT_IF_ERROR(
01544                                 kmclipm_update_property_string(
01545                                     header_sky[ifu_nr-1], EXTNAME, extname,
01546                                     "FITS extension name"));
01547                         cpl_free(extname); extname = NULL;
01548 
01549                         KMO_TRY_EXIT_IF_ERROR(kmo_calc_wcs_gd(main_sky_header,
01550                                     header_sky[ifu_nr-1], ifu_nr, gd));
01551 
01552                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01553                                     header_sky[ifu_nr-1], NAXIS, 3,
01554                                     "number of data axes"));
01555                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01556                                     header_sky[ifu_nr-1], NAXIS1, gd.x.dim,
01557                                     "length of data axis 1"));
01558                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01559                                     header_sky[ifu_nr-1], NAXIS2, gd.y.dim,
01560                                     "length of data axis 2"));
01561                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_int(
01562                                     header_sky[ifu_nr-1], NAXIS3, gd.l.dim,
01563                                     "length of data axis 3"));
01564                         cpl_propertylist_delete(main_sky_header); 
01565                         main_sky_header = NULL;
01566                     }
01567 
01568                     /* Reconstruct object */
01569                     if (ref_spectrum_frame == NULL) {
01570                         /* No lambda correction using OH lines */
01571                         KMO_TRY_EXIT_IF_ERROR(
01572                                 kmo_reconstruct_sci(
01573                                     ifu_nr,
01574                                     bounds[2*(ifu_nr-1)],
01575                                     bounds[2*(ifu_nr-1)+1],
01576                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01577                                     SCIENCE,
01578                                     sky_frame,
01579                                     SCIENCE,
01580                                     flat_frame,
01581                                     xcal_frame,
01582                                     ycal_frame,
01583                                     lcal_frame,
01584                                     NULL,
01585                                     velo_corr_ptr,
01586                                     &gd,
01587                                     &cube_data[ifu_nr-1],
01588                                     &cube_noise[ifu_nr-1],
01589                                     flux,
01590                                     background,
01591                                     xcal_interpolation));
01592                     } else { 
01593                         /* Lambda correction using OH lines */
01594                         KMO_TRY_EXIT_IF_ERROR(
01595                                 kmo_reconstruct_sci(
01596                                     ifu_nr,
01597                                     bounds[2*(ifu_nr-1)],
01598                                     bounds[2*(ifu_nr-1)+1],
01599                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01600                                     SCIENCE,
01601                                     NULL,
01602                                     NULL,
01603                                     flat_frame,
01604                                     xcal_frame,
01605                                     ycal_frame,
01606                                     lcal_frame,
01607                                     NULL,
01608                                     NULL,
01609                                     &gd,
01610                                     &cube_data[ifu_nr-1],
01611                                     &cube_noise[ifu_nr-1],
01612                                     FALSE,
01613                                     FALSE,
01614                                     xcal_interpolation));
01615                         if (cube_data[ifu_nr-1] != NULL) {
01616                             KMO_TRY_EXIT_IF_NULL(
01617                                 oh_lcorr_coeffs = kmo_lcorr_get(
01618                                     cube_data[ifu_nr-1], header_data[ifu_nr-1],
01619                                     ref_spectrum_frame, gd, filter_id, ifu_nr));
01620                             cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01621                             cube_data[ifu_nr-1] = NULL;
01622                             if (cube_noise[ifu_nr-1] != NULL) {
01623                                 cpl_imagelist_delete(cube_noise[ifu_nr-1]); 
01624                                 cube_noise[ifu_nr-1] = NULL;
01625                             }
01626 
01627                             KMO_TRY_EXIT_IF_ERROR(
01628                                     kmo_reconstruct_sci(
01629                                         ifu_nr,
01630                                         bounds[2*(ifu_nr-1)],
01631                                         bounds[2*(ifu_nr-1)+1],
01632                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01633                                         SCIENCE,
01634                                         sky_frame,
01635                                         SCIENCE,
01636                                         flat_frame,
01637                                         xcal_frame,
01638                                         ycal_frame,
01639                                         lcal_frame,
01640                                         oh_lcorr_coeffs,
01641                                         velo_corr_ptr,
01642                                         &gd,
01643                                         &cube_data[ifu_nr-1],
01644                                         &cube_noise[ifu_nr-1],
01645                                         flux,
01646                                         background,
01647                                         xcal_interpolation));
01648                             cpl_polynomial_delete(oh_lcorr_coeffs); 
01649                             oh_lcorr_coeffs = NULL;
01650                         }
01651                     }
01652 
01653                     /* If sky_tweak is set,reconstruct sky frame as object */
01654                     /* and  use kmo_priv_sky_tweak to subtract  */
01655                     /* a modified sky cube */
01656                     if (do_sky_subtraction && sky_tweak) {
01657                         if (ref_spectrum_frame == NULL) {
01658                             /* No lambda correction using OH lines */
01659                             KMO_TRY_EXIT_IF_ERROR(
01660                                     kmo_reconstruct_sci(
01661                                         sky_ifu_nr,
01662                                         bounds[2*(sky_ifu_nr-1)],
01663                                         bounds[2*(sky_ifu_nr-1)+1],
01664                                         sky_as_object_frame,
01665                                         SCIENCE,
01666                                         sky_frame,
01667                                         SCIENCE,
01668                                         flat_frame,
01669                                         xcal_frame,
01670                                         ycal_frame,
01671                                         lcal_frame,
01672                                         NULL,
01673                                         velo_corr_ptr,
01674                                         &gd,
01675                                         &sky_data,
01676                                         &sky_noise,
01677                                         flux,
01678                                         background,
01679                                         xcal_interpolation));
01680                         } else {     
01681                             /* Lambda correction using OH lines */
01682                             KMO_TRY_EXIT_IF_ERROR(
01683                                     kmo_reconstruct_sci(
01684                                         sky_ifu_nr,
01685                                         bounds[2*(sky_ifu_nr-1)],
01686                                         bounds[2*(sky_ifu_nr-1)+1],
01687                                         sky_as_object_frame,
01688                                         SCIENCE,
01689                                         NULL,
01690                                         NULL,
01691                                         flat_frame,
01692                                         xcal_frame,
01693                                         ycal_frame,
01694                                         lcal_frame,
01695                                         NULL,
01696                                         NULL,
01697                                         &gd,
01698                                         &sky_data,
01699                                         &sky_noise,
01700                                         FALSE,
01701                                         FALSE,
01702                                         xcal_interpolation));
01703                             if (sky_data != NULL) {
01704                                 KMO_TRY_EXIT_IF_NULL(
01705                                     oh_lcorr_coeffs = kmo_lcorr_get(sky_data,
01706                                         header_data[ifu_nr-1],
01707                                         ref_spectrum_frame, gd, filter_id,
01708                                         ifu_nr));
01709                                 cpl_imagelist_delete(sky_data); sky_data = NULL;
01710                                 if (sky_noise != NULL) {
01711                                     cpl_imagelist_delete(sky_noise); 
01712                                     sky_noise = NULL;
01713                                 }
01714                                 KMO_TRY_EXIT_IF_ERROR(
01715                                         kmo_reconstruct_sci(
01716                                             sky_ifu_nr,
01717                                             bounds[2*(sky_ifu_nr-1)],
01718                                             bounds[2*(sky_ifu_nr-1)+1],
01719                                             sky_as_object_frame,
01720                                             SCIENCE,
01721                                             sky_frame,
01722                                             SCIENCE,
01723                                             flat_frame,
01724                                             xcal_frame,
01725                                             ycal_frame,
01726                                             lcal_frame,
01727                                             oh_lcorr_coeffs,
01728                                             velo_corr_ptr,
01729                                             &gd,
01730                                             &sky_data,
01731                                             &sky_noise,
01732                                             flux,
01733                                             background,
01734                                             xcal_interpolation));
01735                                 cpl_polynomial_delete(oh_lcorr_coeffs);
01736                                 oh_lcorr_coeffs = NULL;
01737                             }
01738                         } // end if (ref_spectrum_frame == NULL)
01739 
01740                         if (save_interims && (sky_as_object_frame != NULL)) {
01741                             KMO_TRY_EXIT_IF_NULL(cube_interim_object[ifu_nr-1]=
01742                                     cpl_imagelist_duplicate(cube_data[ifu_nr-1]));
01743                             KMO_TRY_EXIT_IF_NULL(cube_interim_sky[ifu_nr-1]=
01744                                     cpl_imagelist_duplicate(sky_data));
01745                         }
01746 
01747                         cpl_imagelist *tmp_object_cube = cube_data[ifu_nr-1];
01748                         KMO_TRY_EXIT_IF_NULL(cube_data[ifu_nr-1] = 
01749                                 kmo_priv_sky_tweak (tmp_object_cube, sky_data,
01750                                     header_data[ifu_nr-1], .3, tbsub));
01751                         if (tmp_object_cube != NULL) {
01752                             cpl_imagelist_delete(tmp_object_cube); 
01753                             tmp_object_cube = NULL;
01754                         }
01755                         if (sky_data != NULL) {
01756                             cpl_imagelist_delete(sky_data); sky_data = NULL;
01757                         }
01758                         if (sky_noise != NULL) {
01759                             cpl_imagelist_delete(sky_noise); sky_noise = NULL;
01760                         }
01761                     } // end if (do_sky_subtraction && sky_tweak)
01762 
01763                     /* Maintain flux constant in case the pixscale is diff */
01764                     /* For example, pixscale=0.1 => images 28x28 => scaling=4 */
01765                     KMO_TRY_EXIT_IF_NULL(
01766                         tmpImg = cpl_imagelist_get(cube_data[ifu_nr-1], 0));
01767                     double scaling = (cpl_image_get_size_x(tmpImg)*
01768                             cpl_image_get_size_y(tmpImg)) /
01769                         (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01770                     KMO_TRY_EXIT_IF_ERROR(
01771                         cpl_imagelist_divide_scalar(cube_data[ifu_nr-1], 
01772                             scaling));
01773                     if (cube_noise[ifu_nr-1] != NULL) {
01774                         KMO_TRY_EXIT_IF_ERROR(
01775                             cpl_imagelist_divide_scalar(cube_noise[ifu_nr-1],
01776                                 scaling));
01777                     }
01778 
01779                     /* Get object name */
01780                     KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s",
01781                                 IFU_NAME_PREFIX, ifu_nr, IFU_NAME_POSTFIX));
01782                     KMO_TRY_EXIT_IF_NULL(tmp_str = cpl_propertylist_get_string(
01783                                 header_data[ifu_nr-1], keyword));
01784                     cpl_free(keyword); keyword = NULL;
01785 
01786                     /* Divide cube by telluric correction */
01787                     if (has_telluric) {
01788                         /* Check if the nb of occurences of the object name  */
01789                         /* is the same as the number of found tellurics for */
01790                         /* this object (which can be on different arms) */
01791                         telluric_ok = FALSE;
01792                         for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01793                             if (((strcmp(arm_name_struct->names[jj], tmp_str) == 0) ||
01794                                  (strcmp(arm_name_struct->names[jj], IFUS_USER_DEFINED) == 0)) &&
01795                                 (arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj])) {
01796                                 telluric_ok = TRUE;
01797                                 break;
01798                             }
01799                         }
01800 
01801                         if (telluric_ok) {
01802                             telluric_data = kmo_tweak_load_telluric(frameset,
01803                                     ifu_nr, FALSE, no_subtract);
01804                             KMO_TRY_CHECK_ERROR_STATE();
01805                             if (telluric_data != NULL) {
01806                                 /* Get the index of the telluric noise */
01807                                 index = kmo_identify_index_desc(desc_telluric,
01808                                         ifu_nr, TRUE);
01809                                 KMO_TRY_CHECK_ERROR_STATE();
01810                                 if (desc_telluric.sub_desc[index-1].valid_data 
01811                                         == TRUE) {
01812                                     // load noise if present
01813                                     telluric_noise = kmo_tweak_load_telluric(
01814                                             frameset,ifu_nr, TRUE, no_subtract);
01815                                     KMO_TRY_CHECK_ERROR_STATE();
01816                                 } else {
01817                                     if (print_warning_once_tweak_std_noise && 
01818                                             (cube_noise[ifu_nr-1] != NULL)) {
01819                                         cpl_msg_warning(__func__,"************************************************************");
01820                                         cpl_msg_warning(__func__,"* Noise cubes were calculated, but won't be divided by     *");
01821                                         cpl_msg_warning(__func__,"* telluric error since it is missing.                      *");
01822                                         cpl_msg_warning(__func__,"* In order to get a telluric with errors, execute          *");
01823                                         cpl_msg_warning(__func__,"* kmo_std_star with one of the nearest neighbour methods   *");
01824                                         cpl_msg_warning(__func__,"* (set --imethod to NN, lwNN or swNN)                      *");
01825                                         cpl_msg_warning(__func__,"************************************************************");
01826                                         print_warning_once_tweak_std_noise = 
01827                                             FALSE;
01828                                     }
01829                                 }
01830 
01831                                 KMO_TRY_EXIT_IF_ERROR(kmo_arithmetic_3D_1D(
01832                                             cube_data[ifu_nr-1], telluric_data,
01833                                             cube_noise[ifu_nr-1],
01834                                             telluric_noise, "/"));
01835                             }
01836                         }
01837                     }
01838 
01839                     /* Divide cube by illumination correction */
01840                     if (has_illum_corr) {
01841                         illum_data = kmo_dfs_load_image(frameset, ILLUM_CORR,
01842                                 ifu_nr, FALSE, FALSE, NULL);
01843                         if (cpl_error_get_code() != CPL_ERROR_NONE) {
01844                             cpl_msg_warning(__func__,
01845                             "No illumination correction for IFU %d available! "
01846                                             "Proceeding anyway.", ifu_nr);
01847                             cpl_error_reset();
01848                         } else {
01849                             illum_noise = kmo_dfs_load_image(frameset,
01850                                     ILLUM_CORR, ifu_nr, TRUE, FALSE, NULL);
01851                             if (cpl_error_get_code() != CPL_ERROR_NONE) {
01852                                 cpl_msg_warning(__func__,
01853                             "No illumination correction for IFU %d available! "
01854                                             "Proceeding anyway.", ifu_nr);
01855                                 cpl_image_delete(illum_data); illum_data = NULL;
01856                                 cpl_error_reset();
01857                             }
01858                         }
01859 
01860                         if (illum_data != NULL) {
01861                             KMO_TRY_EXIT_IF_ERROR(
01862                                 kmo_arithmetic_3D_2D(cube_data[ifu_nr-1],
01863                                     illum_data, cube_noise[ifu_nr-1],
01864                                     illum_noise, "/"));
01865                             cpl_image_delete(illum_data); illum_data = NULL;
01866                             cpl_image_delete(illum_noise); illum_noise = NULL;
01867                         }
01868                     }
01869 
01870                     kmclipm_vector_delete(telluric_data); telluric_data = NULL;
01871                     kmclipm_vector_delete(telluric_noise);telluric_noise= NULL;
01872                 } else {
01873                     // IFU is invalid
01874                 }
01875 
01876                 // duplicate subheader data
01877                 KMO_TRY_EXIT_IF_NULL(header_noise[ifu_nr-1] =
01878                         cpl_propertylist_duplicate(header_data[ifu_nr-1]));
01879                 KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(ifu_frame,
01880                             ifu_nr, EXT_NOISE));
01881                 KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
01882                             header_noise[ifu_nr-1], EXTNAME, extname,
01883                             "FITS extension name"));
01884                 cpl_free(extname); extname = NULL;
01885             } // end for ifu_nr
01886 
01887             /* Count number of reconstructed data- and noise-cubes */
01888             for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
01889                 if (cube_data[ifu_nr-1] != NULL)    cube_counter_data++;
01890                 if (cube_noise[ifu_nr-1] != NULL)   cube_counter_noise++;
01891             }
01892 
01893             /* Save reconstructed cubes of science frame */
01894             if (cube_counter_data > 0) {
01895                 cpl_msg_info(__func__, "   > saving...");
01896 
01897                 if (!suppress_extension) {
01898                     fn_out = fn_obj;
01899 
01900                     int nr_found = 0;
01901                     // remove any path-elements from filename and use it as
01902                     // suffix
01903                     split = kmo_strsplit(fn_out, "/", &nr_found);
01904 
01905                     fn_suffix = cpl_sprintf("_%s", split[nr_found-1]);
01906                     kmo_strfreev(split);
01907 
01908                     // remove '.fits' at the end if there is any
01909                     char *fff = fn_suffix;
01910                     fff += strlen(fn_suffix)-5;
01911                     if (strcmp(fff, ".fits") == 0) {
01912                         fn_suffix[strlen(fn_suffix)-5] = '\0';
01913                     }
01914                 } else {
01915                     KMO_TRY_EXIT_IF_NULL(
01916                         fn_suffix = cpl_sprintf("_%d", suppress_index++));
01917                 }
01918 
01919                 fn_out = RECONSTRUCTED_CUBE;
01920                 fn_interim_object = INTERIM_OBJECT_CUBE;
01921                 fn_interim_sky = INTERIM_OBJECT_SKY;
01922 
01923                 /* Create Primary Header */
01924                 KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01925                             fn_out, fn_suffix,
01926                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01927                             NULL, parlist, cpl_func));
01928                 /* save intermediate products (only in sky tweak case) */
01929                 if (save_interims && (sky_as_object_frame != NULL)) {
01930                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01931                                 fn_interim_object, fn_suffix,
01932                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01933                             NULL, parlist, cpl_func));
01934                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
01935                                 fn_interim_sky, fn_suffix,
01936                                 arm_name_struct->obj_sky_struct->table[sf].objFrame,
01937                                 NULL, parlist, cpl_func));
01938                 }
01939 
01940                 /* Loop on IFUs */
01941                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01942                     /* Save data Extension */
01943                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(cube_data[ifu_nr-1],
01944                                 fn_out,fn_suffix,header_data[ifu_nr-1], 0./0.));
01945 
01946                     /* Save noise Extension */
01947                     if (cube_counter_noise > 0) {
01948                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01949                                     cube_noise[ifu_nr-1], fn_out, fn_suffix,
01950                                     header_noise[ifu_nr-1], 0./0.));
01951                     }
01952 
01953                     /* save intermediate products (only in sky tweak case */
01954                     if (save_interims && (sky_as_object_frame != NULL)) {
01955                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01956                                     cube_interim_object[ifu_nr-1],
01957                                     fn_interim_object, fn_suffix,
01958                                     header_data[ifu_nr-1], 0./0.));
01959                         KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(
01960                                     cube_interim_sky[ifu_nr-1], fn_interim_sky,
01961                                     fn_suffix, header_sky[ifu_nr-1], 0./0.));
01962                     }
01963 
01964                     cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01965                     cube_data[ifu_nr-1] = NULL;
01966                     cpl_imagelist_delete(cube_noise[ifu_nr-1]);
01967                     cube_noise[ifu_nr-1] = NULL;
01968                     cpl_propertylist_delete(header_data[ifu_nr-1]);
01969                     header_data[ifu_nr-1] = NULL;
01970                     cpl_propertylist_delete(header_noise[ifu_nr-1]);
01971                     header_noise[ifu_nr-1] = NULL;
01972                     if (save_interims) {
01973                         cpl_imagelist_delete(cube_interim_object[ifu_nr-1]);
01974                         cube_interim_object[ifu_nr-1] = NULL;
01975                         cpl_imagelist_delete(cube_interim_sky[ifu_nr-1]);
01976                         cube_interim_sky[ifu_nr-1] = NULL;
01977                         cpl_propertylist_delete(header_sky[ifu_nr-1]);
01978                         header_sky[ifu_nr-1] = NULL;
01979                     }
01980                 } // end for ifu_nr
01981                 cpl_free(fn_suffix); fn_suffix = NULL;
01982             } else {
01983                 cpl_msg_info(__func__, "   > all IFUs invalid, don't save");
01984                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01985                     cpl_propertylist_delete(header_data[ifu_nr-1]); 
01986                     header_data[ifu_nr-1] = NULL;
01987                     cpl_propertylist_delete(header_noise[ifu_nr-1]); 
01988                     header_noise[ifu_nr-1] = NULL;
01989                 }
01990             } // if (cube_counter_data > 0) {
01991 
01992             cpl_propertylist_delete(main_header); main_header = NULL;
01993         } // end for sf (arm_name_struct->obj_sky_struct->size)
01994         cpl_free(cube_data);    cube_data = NULL;
01995         cpl_free(cube_noise);    cube_noise = NULL;
01996         cpl_free(header_data);    header_data = NULL;
01997         cpl_free(header_noise);    header_noise = NULL;
01998         if (save_interims) {
01999             cpl_free(cube_interim_object);    cube_interim_object = NULL;
02000             cpl_free(cube_interim_sky);       cube_interim_sky = NULL;
02001             cpl_free(header_sky);             header_sky = NULL;
02002         }
02003 
02004         kmo_print_unused_ifus(unused_ifus_after, TRUE);
02005 
02006         cpl_msg_info("", "-------------------------------------------");
02007 
02008         if (lcal != NULL) {
02009             for (i = 0; i < KMOS_NR_DETECTORS; i++) {
02010                 cpl_image_delete(lcal[i]);
02011             }
02012         }
02013         cpl_free(lcal); lcal = NULL;
02014 
02015         /* Combine */
02016         suppress_index = 0;
02017         if (!no_combine) {
02018             cpl_msg_info(__func__, "Combining reconstructed objects");
02019             nr_reconstructed_frames = cpl_frameset_count_tags(frameset,
02020                     RECONSTRUCTED_CUBE);
02021             if ((mapping_mode == NULL) || ((mapping_mode != NULL) &&
02022                         ((ifus != NULL) || (strcmp(name, "") != 0)))) {
02023                 // loop all available objects
02024                 for (i = 0; i < arm_name_struct->nrNames; i++) {
02025                     cpl_msg_info(__func__, 
02026                             "   > object: %s", arm_name_struct->names[i]);
02027                     nr_data_alloc = arm_name_struct->namesCnt[i];
02028                     KMO_TRY_EXIT_IF_NULL(cube_data=(cpl_imagelist**)cpl_calloc(
02029                                 nr_data_alloc, sizeof(cpl_imagelist*)));
02030                     KMO_TRY_EXIT_IF_NULL(cube_noise=(cpl_imagelist**)cpl_calloc(
02031                                 nr_data_alloc, sizeof(cpl_imagelist*)));
02032                     KMO_TRY_EXIT_IF_NULL(header_data=
02033                             (cpl_propertylist**)cpl_calloc(nr_data_alloc,
02034                                 sizeof(cpl_propertylist*)));
02035                     KMO_TRY_EXIT_IF_NULL(header_noise=
02036                             (cpl_propertylist**)cpl_calloc(nr_data_alloc,
02037                                 sizeof(cpl_propertylist*)));
02038 
02039                     // setup cube-list and header-list for kmo_priv_combine()
02040                     cube_counter_data = 0;
02041                     cube_counter_noise = 0;
02042                     KMO_TRY_EXIT_IF_NULL(tmp_frame = kmo_dfs_get_frame(frameset,
02043                                 RECONSTRUCTED_CUBE));
02044                     while (tmp_frame != NULL ) {
02045                         KMO_TRY_EXIT_IF_NULL(
02046                             fn_reconstr = cpl_frame_get_filename(tmp_frame));
02047                         KMO_TRY_EXIT_IF_NULL(tmp_header = 
02048                                 kmclipm_propertylist_load(fn_reconstr, 0));
02049                         kmo_free_fits_desc(&desc1);
02050                         kmo_init_fits_desc(&desc1);
02051                         desc1 = kmo_identify_fits_header(fn_reconstr);
02052 
02053                         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
02054                             // check if object-name equals the one in our list
02055                             KMO_TRY_EXIT_IF_NULL(keyword = cpl_sprintf("%s%d%s",
02056                                         IFU_NAME_PREFIX, ifu_nr, 
02057                                         IFU_NAME_POSTFIX));
02058                             KMO_TRY_EXIT_IF_NULL(tmp_str = 
02059                                     cpl_propertylist_get_string(tmp_header,
02060                                         keyword));
02061                             cpl_free(keyword); keyword = NULL;
02062 
02063                             if ((strcmp(arm_name_struct->names[i],tmp_str)==0)
02064                                     || (strcmp(arm_name_struct->names[i],
02065                                             IFUS_USER_DEFINED) == 0)) {
02066                                 // found object-IFU with matching name
02067                                 // load data & subheader
02068                                 index = kmo_identify_index(fn_reconstr, ifu_nr,
02069                                         FALSE);
02070                                 KMO_TRY_CHECK_ERROR_STATE();
02071 
02072                                 if (desc1.sub_desc[index-1].valid_data) {
02073                                     KMO_TRY_EXIT_IF_NULL(
02074                                         cube_data[cube_counter_data] =
02075                                             kmclipm_imagelist_load(fn_reconstr,
02076                                                 CPL_TYPE_FLOAT, index));
02077         /* Set cubes borders (1 pixel) to Nan to avoid jumps in combined cube */
02078                                     if (edge_nan) {
02079                                         KMO_TRY_EXIT_IF_ERROR(kmo_edge_nan(
02080                                                     cube_data[cube_counter_data], 
02081                                                     ifu_nr));
02082                                     }
02083 
02084                                     KMO_TRY_EXIT_IF_NULL(
02085                                         header_data[cube_counter_data] =
02086                                             kmclipm_propertylist_load(
02087                                                 fn_reconstr, index));
02088                                     cpl_propertylist_update_string(
02089                                             header_data[cube_counter_data],
02090                                             "ESO PRO FRNAME", fn_reconstr);
02091                                     cpl_propertylist_update_int(
02092                                             header_data[cube_counter_data],
02093                                             "ESO PRO IFUNR", ifu_nr);
02094                                     cube_counter_data++;
02095                                 }
02096 
02097                                 // load noise & subheader (if existing)
02098                                 if (desc1.ex_noise) {
02099                                     index = kmo_identify_index(fn_reconstr,
02100                                             ifu_nr, TRUE);
02101                                     KMO_TRY_CHECK_ERROR_STATE();
02102 
02103                                     if (desc1.sub_desc[index-1].valid_data) {
02104                                         KMO_TRY_EXIT_IF_NULL(
02105                                             cube_noise[cube_counter_noise] =
02106                                                 kmclipm_imagelist_load(
02107                                                     fn_reconstr, CPL_TYPE_FLOAT,
02108                                                     index));
02109                                         if (edge_nan) {
02110                                             KMO_TRY_EXIT_IF_ERROR(
02111                                                 kmo_edge_nan(cube_noise[cube_counter_noise], ifu_nr));
02112                                         }
02113                                         KMO_TRY_EXIT_IF_NULL(
02114                                             header_noise[cube_counter_noise] =
02115                                                 kmclipm_propertylist_load(
02116                                                     fn_reconstr, index));
02117                                         cube_counter_noise++;
02118                                     }
02119                                 }
02120                                 cpl_error_reset();
02121                             } // end if found obj
02122                         } // end for ifu_nr
02123 
02124                         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02125                         tmp_frame = kmo_dfs_get_frame(frameset, NULL);
02126                         KMO_TRY_CHECK_ERROR_STATE();
02127                     } // end while-loop RECONSTRUCTED_CUBE frames
02128 
02129                     if (cube_counter_data > 1) {
02130                         if (cube_counter_data == cube_counter_noise) {
02131                             KMO_TRY_EXIT_IF_ERROR(
02132                                 kmo_priv_combine(cube_data,
02133                                     cube_noise,
02134                                     header_data,
02135                                     header_noise,
02136                                     cube_counter_data,
02137                                     cube_counter_noise,
02138                                     arm_name_struct->names[i],
02139                                     "",
02140                                     comb_method,
02141                                     smethod,
02142                                     fmethod,
02143                                     filename,
02144                                     cmethod,
02145                                     cpos_rej,
02146                                     cneg_rej,
02147                                     citer,
02148                                     cmin,
02149                                     cmax,
02150                                     extrapol_enum,
02151                                     flux,
02152                                     &combined_data,
02153                                     &combined_noise,
02154                                     &exp_mask));
02155                         } else if (cube_counter_noise == 0) {
02156                             KMO_TRY_EXIT_IF_ERROR(
02157                                 kmo_priv_combine(cube_data,
02158                                     NULL,
02159                                     header_data,
02160                                     header_noise,
02161                                     cube_counter_data,
02162                                     cube_counter_noise,
02163                                     arm_name_struct->names[i],
02164                                     "",
02165                                     comb_method,
02166                                     smethod,
02167                                     fmethod,
02168                                     filename,
02169                                     cmethod,
02170                                     cpos_rej,
02171                                     cneg_rej,
02172                                     citer,
02173                                     cmin,
02174                                     cmax,
02175                                     extrapol_enum,
02176                                     flux,
02177                                     &combined_data,
02178                                     &combined_noise,
02179                                     &exp_mask));
02180                         } else {
02181                             KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
02182                                     "The number of cube-data and cube-noise "
02183                                     "isn't the same (%d vs. %d)!",
02184                                     cube_counter_data, cube_counter_noise);
02185                         }
02186                     } else if (cube_counter_data == 1) {
02187                         cpl_msg_warning(__func__, 
02188                                 "There is only one reconstructed cube with "
02189                                 "this object! Saving it as it is.");
02190                         KMO_TRY_EXIT_IF_NULL(combined_data = 
02191                                 cpl_imagelist_duplicate(cube_data[0]));
02192                         KMO_TRY_EXIT_IF_NULL(tmpImg = 
02193                                 cpl_imagelist_get(combined_data, 0));
02194                         KMO_TRY_EXIT_IF_NULL(exp_mask = cpl_image_new(
02195                                     cpl_image_get_size_x(tmpImg),
02196                                     cpl_image_get_size_y(tmpImg), 
02197                                     CPL_TYPE_FLOAT));
02198                         KMO_TRY_EXIT_IF_ERROR(kmo_image_fill(exp_mask, 1.));
02199 
02200                         if (cube_noise[0] != NULL) {
02201                             KMO_TRY_EXIT_IF_NULL(
02202                                 combined_noise = cpl_imagelist_duplicate(
02203                                     cube_noise[0]));
02204                         }
02205                     } else {
02206                         KMO_TRY_ASSURE(1==0, CPL_ERROR_ILLEGAL_INPUT,
02207                                 "No cubes found with this object name!");
02208                     } // end if (cube_counter_data > 1)
02209 
02210                     fn_out = COMBINED_CUBE;
02211                     fn_out_mask = EXP_MASK;
02212                     if (!suppress_extension) {
02213                         char tmp_suffix[1024];
02214                         tmp_suffix[0] = '\0';
02215 
02216                         if (arm_name_struct->telluricCnt[i] == 
02217                                 arm_name_struct->namesCnt[i]) {
02218                             strcat(tmp_suffix, "_telluric");
02219                         }
02220                         if (has_illum_corr)     strcat(tmp_suffix, "_illum");
02221                         if (sky_tweak)          strcat(tmp_suffix, "_skytweak");
02222 
02223                         if (strlen(tmp_suffix) > 0) {
02224                             KMO_TRY_EXIT_IF_NULL(
02225                                 fn_suffix = cpl_sprintf("_%s_%s", 
02226                                     arm_name_struct->names[i], tmp_suffix));
02227                         } else {
02228                             KMO_TRY_EXIT_IF_NULL(
02229                                 fn_suffix = cpl_sprintf("_%s", 
02230                                     arm_name_struct->names[i]));
02231                         }
02232                     } else {
02233                         KMO_TRY_EXIT_IF_NULL(
02234                             fn_suffix = cpl_sprintf("_%d", suppress_index++));
02235                     }
02236 
02237                     // save combined cube
02238                     KMO_TRY_EXIT_IF_NULL(tmp_frame = 
02239                             kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE));
02240                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
02241                                 fn_out, fn_suffix, tmp_frame, NULL, parlist, 
02242                                 cpl_func));
02243                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_main_header(frameset, 
02244                                 fn_out_mask, fn_suffix, tmp_frame, NULL, 
02245                                 parlist, cpl_func));
02246                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(combined_data, 
02247                                 fn_out, fn_suffix, header_data[0], 0./0.));
02248                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_image(exp_mask, 
02249                                 fn_out_mask, fn_suffix, header_data[0], 0./0.));
02250                         
02251                     if (header_noise[0] == NULL) {
02252                         KMO_TRY_EXIT_IF_NULL(header_noise[0] = 
02253                                 cpl_propertylist_duplicate(header_data[0]));
02254 
02255                         KMO_TRY_EXIT_IF_NULL(tmp_str = 
02256                                 cpl_propertylist_get_string(header_data[0], 
02257                                     EXTNAME));
02258                         KMO_TRY_EXIT_IF_ERROR(kmo_extname_extractor(tmp_str, 
02259                                     &ft, &tmp_int, content));
02260                         KMO_TRY_EXIT_IF_NULL(extname = kmo_extname_creator(
02261                                     ifu_frame, tmp_int, EXT_NOISE));
02262                         KMO_TRY_EXIT_IF_ERROR(kmclipm_update_property_string(
02263                                     header_noise[0], EXTNAME, extname,
02264                                     "FITS extension name"));
02265                         cpl_free(extname); extname = NULL;
02266                     }
02267                     KMO_TRY_EXIT_IF_ERROR(kmo_dfs_save_cube(combined_noise, 
02268                                 fn_out, fn_suffix, header_noise[0], 0./0.));
02269 
02270                     for (jj = 0; jj < nr_data_alloc; jj++) {
02271                         cpl_imagelist_delete(cube_data[jj]); 
02272                         cube_data[jj] = NULL;
02273                         cpl_imagelist_delete(cube_noise[jj]); 
02274                         cube_noise[jj] = NULL;
02275                         cpl_propertylist_delete(header_data[jj]); 
02276                         header_data[jj] = NULL;
02277                         cpl_propertylist_delete(header_noise[jj]); 
02278                         header_noise[jj] = NULL;
02279                     }
02280                     cpl_free(cube_data);    cube_data = NULL;
02281                     cpl_free(cube_noise);   cube_noise = NULL;
02282                     cpl_free(header_data);  header_data = NULL;
02283                     cpl_free(header_noise); header_noise = NULL;
02284                     cpl_free(fn_suffix); fn_suffix = NULL;
02285                     cpl_imagelist_delete(combined_data); combined_data = NULL;
02286                     cpl_imagelist_delete(combined_noise); combined_noise = NULL;
02287                     cpl_image_delete(exp_mask); exp_mask = NULL;
02288                 } // for i = nr_avail_obj_names
02289             } else {
02290                 // we are in mapping_mode
02291                 nr_data_alloc = nr_reconstructed_frames*KMOS_NR_IFUS;
02292                 KMO_TRY_EXIT_IF_NULL(cube_data = (cpl_imagelist**)cpl_calloc(
02293                             nr_data_alloc, sizeof(cpl_imagelist*)));
02294                 KMO_TRY_EXIT_IF_NULL(cube_noise = (cpl_imagelist**)cpl_calloc(
02295                             nr_data_alloc, sizeof(cpl_imagelist*)));
02296                 KMO_TRY_EXIT_IF_NULL(header_data=(cpl_propertylist**)cpl_calloc(
02297                             nr_data_alloc, sizeof(cpl_propertylist*)));
02298                 KMO_TRY_EXIT_IF_NULL(header_noise=(cpl_propertylist**)cpl_calloc(
02299                             nr_data_alloc, sizeof(cpl_propertylist*)));
02300 
02301                 cube_counter_data = 0;
02302                 cube_counter_noise = 0;
02303                 KMO_TRY_EXIT_IF_NULL(tmp_frame = 
02304                         kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE));
02305                 while (tmp_frame != NULL ) {
02306                     KMO_TRY_EXIT_IF_NULL(
02307                         fn_reconstr = cpl_frame_get_filename(tmp_frame));
02308                     KMO_TRY_EXIT_IF_NULL(
02309                         tmp_header = kmclipm_propertylist_load(fn_reconstr, 0));
02310 
02311                     kmo_free_fits_desc(&desc1);
02312                     kmo_init_fits_desc(&desc1);
02313                     desc1 = kmo_identify_fits_header(fn_reconstr);
02314                     for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
02315                         index = kmo_identify_index(fn_reconstr, ifu_nr, FALSE);
02316                         KMO_TRY_CHECK_ERROR_STATE();
02317 
02318                         if (desc1.sub_desc[index-1].valid_data) {
02319                             KMO_TRY_EXIT_IF_NULL(cube_data[cube_counter_data] =
02320                                     kmclipm_imagelist_load(fn_reconstr, 
02321                                         CPL_TYPE_FLOAT, index));
02322                             if (edge_nan) {
02323                                 KMO_TRY_EXIT_IF_ERROR(
02324                                     kmo_edge_nan(cube_data[cube_counter_data], 
02325                                         ifu_nr));
02326                             }
02327 
02328                             if (fast_mode) {
02329                                 KMO_TRY_EXIT_IF_NULL(tmpImg = 
02330                                         cpl_imagelist_collapse_median_create(
02331                                             cube_data[cube_counter_data]));
02332                                 KMO_TRY_EXIT_IF_NULL(
02333                                     tmpCube = cpl_imagelist_new());
02334                                 KMO_TRY_EXIT_IF_ERROR(
02335                                     cpl_imagelist_set(tmpCube, tmpImg, 0));
02336                                 cpl_imagelist_delete(cube_data[cube_counter_data]);
02337                                 cube_data[cube_counter_data] = tmpCube;
02338                             }
02339 
02340                             KMO_TRY_EXIT_IF_NULL(
02341                                 header_data[cube_counter_data] =
02342                                     kmclipm_propertylist_load(fn_reconstr, index));
02343                             cpl_propertylist_update_string(
02344                                     header_data[cube_counter_data], 
02345                                     "ESO PRO FRNAME", fn_reconstr);
02346                             cpl_propertylist_update_int(
02347                                     header_data[cube_counter_data], 
02348                                     "ESO PRO IFUNR", ifu_nr);
02349                             cube_counter_data++;
02350                         }
02351 
02352                         // load noise & subheader (if existing)
02353                         if (desc1.ex_noise) {
02354                             index = kmo_identify_index(fn_reconstr,ifu_nr,TRUE);
02355                             KMO_TRY_CHECK_ERROR_STATE();
02356                             if (desc1.sub_desc[index-1].valid_data) {
02357                                 KMO_TRY_EXIT_IF_NULL(
02358                                     cube_noise[cube_counter_noise] =
02359                                         kmclipm_imagelist_load(fn_reconstr, 
02360                                             CPL_TYPE_FLOAT, index));
02361 
02362                                 if (edge_nan) {
02363                                     KMO_TRY_EXIT_IF_ERROR(kmo_edge_nan(
02364                                                 cube_noise[cube_counter_noise],
02365                                                 ifu_nr));
02366                                 }
02367 
02368                                 if (fast_mode) {
02369                                     KMO_TRY_EXIT_IF_NULL(tmpImg = 
02370                                             cpl_imagelist_collapse_median_create(cube_noise[cube_counter_noise]));
02371                                     KMO_TRY_EXIT_IF_NULL(
02372                                         tmpCube = cpl_imagelist_new());
02373                                     KMO_TRY_EXIT_IF_ERROR(
02374                                         cpl_imagelist_set(tmpCube, tmpImg, 0));
02375                                     cpl_imagelist_delete(cube_noise[cube_counter_noise]);
02376                                     cube_noise[cube_counter_noise] = tmpCube;
02377                                 }
02378                                 KMO_TRY_EXIT_IF_NULL(
02379                                     header_noise[cube_counter_noise] = 
02380                                     kmclipm_propertylist_load(fn_reconstr,
02381                                         index));
02382                                 cube_counter_noise++;
02383                             }
02384                         }
02385                         cpl_error_reset();
02386                     } // end for ifu_nr
02387 
02388                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02389                     tmp_frame = kmo_dfs_get_frame(frameset, NULL);
02390                     KMO_TRY_CHECK_ERROR_STATE();
02391                 } // end while-loop RECONSTRUCTED_CUBE frames
02392 
02393                 if (cube_counter_data > 1) {
02394                     if (cube_counter_data == cube_counter_noise) {
02395                         KMO_TRY_EXIT_IF_ERROR(
02396                             kmo_priv_combine(cube_data,
02397                                 cube_noise,
02398                                 header_data,
02399                                 header_noise,
02400                                 cube_counter_data,
02401                                 cube_counter_noise,
02402                                 mapping_mode,
02403                                 "",
02404                                 comb_method,
02405                                 smethod,
02406                                 fmethod,
02407                                 filename,
02408                                 cmethod,
02409                                 cpos_rej,
02410                                 cneg_rej,
02411                                 citer,
02412                                 cmin,
02413                                 cmax,
02414                                 extrapol_enum,
02415                                 flux,
02416                                 &combined_data,
02417                                 &combined_noise,
02418                                 NULL));
02419                     } else if (cube_counter_noise == 0) {
02420                         KMO_TRY_EXIT_IF_ERROR(
02421                             kmo_priv_combine(cube_data,
02422                                 NULL,
02423                                 header_data,
02424                                 header_noise,
02425                                 cube_counter_data,
02426                                 cube_counter_noise,
02427                                 mapping_mode,
02428                                 "",
02429                                 comb_method,
02430                                 smethod,
02431                                 fmethod,
02432                                 filename,
02433                                 cmethod,
02434                                 cpos_rej,
02435                                 cneg_rej,
02436                                 citer,
02437                                 cmin,
02438                                 cmax,
02439                                 extrapol_enum,
02440                                 flux,
02441                                 &combined_data,
02442                                 &combined_noise,
02443                                 NULL));
02444                     } else {
02445                         KMO_TRY_ASSURE(1 == 0, CPL_ERROR_ILLEGAL_INPUT,
02446                                 "The number of cube-data and cube-noise "
02447                                 "isn't the same (%d vs. %d)!",
02448                                 cube_counter_data, cube_counter_noise);
02449                     }
02450                 } else {
02451                     cpl_msg_warning(__func__, 
02452                             "There is only one reconstructed cube - Save it");
02453                     KMO_TRY_EXIT_IF_NULL(
02454                         combined_data = cpl_imagelist_duplicate(cube_data[0]));
02455 
02456                     if (cube_noise[0] != NULL) {
02457                         KMO_TRY_EXIT_IF_NULL(
02458                             combined_noise = cpl_imagelist_duplicate(
02459                                 cube_noise[0]));
02460                     }
02461                 }
02462 
02463                 fn_out = COMBINED_CUBE;
02464                 KMO_TRY_EXIT_IF_NULL(
02465                     fn_suffix = cpl_sprintf("_%s", mapping_mode));
02466 
02467                 // save combined cube
02468                 KMO_TRY_EXIT_IF_NULL(tmp_frame = kmo_dfs_get_frame(frameset,
02469                             RECONSTRUCTED_CUBE));
02470                 KMO_TRY_EXIT_IF_ERROR(
02471                     kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, 
02472                         tmp_frame, NULL, parlist, cpl_func));
02473 
02474                 KMO_TRY_EXIT_IF_ERROR(
02475                     kmo_dfs_save_cube(combined_data, fn_out, fn_suffix,
02476                         header_data[0], 0./0.));
02477 
02478                 if (header_noise[0] == NULL) {
02479                     KMO_TRY_EXIT_IF_NULL(
02480                         header_noise[0] =
02481                              cpl_propertylist_duplicate(header_data[0]));
02482 
02483                     KMO_TRY_EXIT_IF_NULL(
02484                         tmp_str = cpl_propertylist_get_string(header_data[0],
02485                             EXTNAME));
02486                     KMO_TRY_EXIT_IF_ERROR(
02487                         kmo_extname_extractor(tmp_str, &ft, &tmp_int, content));
02488                     KMO_TRY_EXIT_IF_NULL(
02489                         extname = kmo_extname_creator(ifu_frame, tmp_int,
02490                             EXT_NOISE));
02491                     KMO_TRY_EXIT_IF_ERROR(
02492                         kmclipm_update_property_string(header_noise[0], EXTNAME,
02493                             extname, "FITS extension name"));
02494                     cpl_free(extname); extname = NULL;
02495                 }
02496                 KMO_TRY_EXIT_IF_ERROR(
02497                     kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix,
02498                         header_noise[0], 0./0.));
02499 
02500                 for (i = 0; i < nr_data_alloc; i++) {
02501                     cpl_imagelist_delete(cube_data[i]); cube_data[i] = NULL;
02502                     cpl_imagelist_delete(cube_noise[i]); cube_noise[i] = NULL;
02503                     cpl_propertylist_delete(header_data[i]); 
02504                     header_data[i] = NULL;
02505                     cpl_propertylist_delete(header_noise[i]); 
02506                     header_noise[i] = NULL;
02507                 }
02508                 cpl_free(cube_data);    cube_data = NULL;
02509                 cpl_free(cube_noise);   cube_noise = NULL;
02510                 cpl_free(header_data);  header_data = NULL;
02511                 cpl_free(header_noise); header_noise = NULL;
02512                 cpl_free(fn_suffix); fn_suffix = NULL;
02513                 cpl_imagelist_delete(combined_data); combined_data = NULL;
02514                 cpl_imagelist_delete(combined_noise); combined_noise = NULL;
02515             } // if mapping_mode
02516         } else {
02517             cpl_msg_info("", "Reconstructed objects are not combined");
02518         } // if (!no_combine)
02519         cpl_msg_info("", "-------------------------------------------");
02520     }
02521     KMO_CATCH
02522     {
02523         KMO_CATCH_MSG();
02524         ret_val = -1;
02525     }
02526     if (cube_data != NULL) {
02527         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02528             cpl_imagelist_delete(cube_data[ifu_nr-1]); 
02529             cube_data[ifu_nr-1] = NULL;
02530         }
02531     }
02532     cpl_free(cube_data);    cube_data = NULL;
02533     if (cube_noise != NULL) {
02534         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02535             cpl_imagelist_delete(cube_noise[ifu_nr-1]); 
02536             cube_noise[ifu_nr-1] = NULL;
02537         }
02538     }
02539     cpl_free(cube_noise);   cube_noise = NULL;
02540     if (header_data != NULL) {
02541         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02542             cpl_propertylist_delete(header_data[ifu_nr-1]);
02543             header_data[ifu_nr-1] = NULL;
02544         }
02545     }
02546     cpl_free(header_data);  header_data = NULL;
02547     if (header_noise != NULL) {
02548         for (ifu_nr = 1; ifu_nr <= nr_data_alloc; ifu_nr++) {
02549             cpl_propertylist_delete(header_noise[ifu_nr-1]);
02550             header_noise[ifu_nr-1] = NULL;
02551         }
02552     }
02553     cpl_free(header_noise); header_noise = NULL;
02554 
02555 
02556     kmo_free_fits_desc(&desc1);
02557     kmo_free_fits_desc(&desc2);
02558     kmo_free_fits_desc(&desc_telluric);
02559 
02560     cpl_vector_delete(ifus); ifus = NULL;
02561     cpl_free(mapping_mode); mapping_mode = NULL;
02562     if (unused_ifus_before != NULL) {
02563         kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL;
02564     }
02565     if (unused_ifus_after != NULL) {
02566         kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL;
02567     }
02568     if (bounds != NULL) {
02569         cpl_free(bounds); bounds = NULL;
02570     }
02571 
02572     // frees for the case of errors
02573     kmclipm_vector_delete(telluric_data); telluric_data = NULL;
02574     kmclipm_vector_delete(telluric_noise); telluric_noise = NULL;
02575     cpl_image_delete(illum_data); illum_data = NULL;
02576     cpl_image_delete(illum_noise); illum_noise = NULL;
02577     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
02578     cpl_table_delete(band_table); band_table = NULL;
02579     cpl_propertylist_delete(main_header); main_header = NULL;
02580     if (lcal != NULL) {
02581         for (i = 0; i < KMOS_NR_DETECTORS; i++) {
02582             cpl_image_delete(lcal[i]);
02583         }
02584     }
02585     cpl_free(lcal); lcal = NULL;
02586     cpl_free(fn_suffix); fn_suffix = NULL;
02587     cpl_free(suffix); suffix = NULL;
02588 
02589     kmo_delete_armNameStruct(arm_name_struct);
02590 
02591     return ret_val;
02592 }
02593