KMOS Pipeline Reference Manual  1.3.11
kmos_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_make_image.h"
00045 
00046 #include "kmo_priv_arithmetic.h"
00047 #include "kmo_priv_combine.h"
00048 #include "kmo_priv_functions.h"
00049 #include "kmo_priv_reconstruct.h"
00050 #include "kmos_priv_sky_tweak.h"
00051 
00052 /*-----------------------------------------------------------------------------
00053  *                          Functions prototypes
00054  *----------------------------------------------------------------------------*/
00055 
00056 static double kmos_sci_red_get_f0(const char *, int, double, double) ;
00057 static double kmos_sci_red_get_zpoint(cpl_frame *, int) ;
00058 static int kmos_sci_red_clean_plist(cpl_propertylist *) ;
00059 static int kmos_sci_red_collapse_cubes(char *, cpl_frameset *, 
00060         cpl_parameterlist *, double, const char *, const char *, double, 
00061         double, int, int, int) ;
00062 static int kmos_sci_red_check_inputs(cpl_frameset *, int *);
00063 
00064 static int kmos_sci_red_create(cpl_plugin *);
00065 static int kmos_sci_red_exec(cpl_plugin *);
00066 static int kmos_sci_red_destroy(cpl_plugin *);
00067 static int kmos_sci_red(cpl_parameterlist *, cpl_frameset *);
00068 
00069 /*-----------------------------------------------------------------------------
00070  *                          Static variables
00071  *----------------------------------------------------------------------------*/
00072 
00073 static char kmos_sci_red_description[] =
00074 "Two data frames are expected in order to have a sky IFU for the IFU Objects.\n"
00075 "If an OH spectrum is given in the SOF file the lambda axis will be corrected\n"
00076 "using the OH lines as reference.\n"
00077 "Every IFU containing an object will be reconstructed and divided by telluric\n"
00078 "and illumination correction. By default these intermediate cubes are saved\n"
00079 "to disk. The reconstructed objects with the same object name are combined.\n"
00080 "In order to combine a specific object, the parameters --name or --ifus can\n"
00081 "be used.\n"
00082 "For exposures taken with the templates KMOS_spec_obs_mapping8 and\n"
00083 "KMOS_spec_obs_mapping24, all active IFUs are combined.\n"
00084 "\n"
00085 "--------------------------------------------------------------------------\n"
00086 "  Input files:\n"
00087 "\n"
00088 "   DO                KMOS                                                 \n"
00089 "   category          Type   Explanation                   Required #Frames\n"
00090 "   --------          -----  -----------                   -------- -------\n"
00091 "   SCIENCE           RAW    The science frames                Y      >=1  \n"
00092 "   XCAL              F2D    x calibration frame               Y       1   \n"
00093 "   YCAL              F2D    y calibration frame               Y       1   \n"
00094 "   LCAL              F2D    Wavelength calib. frame           Y       1   \n"
00095 "   WAVE_BAND         F2L    Table with start-/end-wavelengths Y       1   \n"
00096 "   MASTER_FLAT       F2D    Master flat                       Y      0,1  \n"
00097 "   ILLUM_CORR        F2I    Illumination correction           N      0,1  \n"
00098 "   TELLURIC          F1I    normalised telluric spectrum      N      0,1  \n"
00099 "   OH_SPEC           F1S    Vector holding OH lines           N      0,1  \n"
00100 "\n"
00101 "  Output files:\n"
00102 "\n"
00103 "   DO                KMOS\n"
00104 "   category          Type   Explanation\n"
00105 "   --------              -----  -----------\n"
00106 "   SCI_COMBINED      F3I    Combined cubes with noise\n"
00107 "   SCI_RECONSTRUCTED F3I    Reconstructed cube with noise\n"
00108 "   EXP_MASK          F3I    Exposure time mask (not for mapping-templates!)\n"
00109 "   SCI_INTERIM_OBJECT F3I    (optional) Intermediate reconstructed object \n"
00110 "                            cubes used for sky tweaking, no noise \n"
00111 "                            (set --sky_tweak and --save_interims)\n"
00112 "   SCI_INTERIM_SKY   F3I    (optional) Intermediate reconstructed sky \n"
00113 "                            cubes used for sky tweaking, no noise\n"
00114 "                            (set --sky_tweak and --save_interims)\n"
00115 "   SCI_COMBINED_COLL        (optional) Collapsed combined cube\n"
00116 "                            (set --collapse_combined)\n"
00117 "   SCI_RECONSTRUCTED_COLL   (optional) Collapsed reconstructed cube\n"
00118 "                            (set --collapse_reconstructed)\n"
00119 "--------------------------------------------------------------------------\n"
00120 "\n";
00121 
00122 /*-----------------------------------------------------------------------------
00123  *                              Functions code
00124  *----------------------------------------------------------------------------*/
00125 
00126 /*----------------------------------------------------------------------------*/
00131 /*----------------------------------------------------------------------------*/
00132 
00135 /*----------------------------------------------------------------------------*/
00144 /*----------------------------------------------------------------------------*/
00145 int cpl_plugin_get_info(cpl_pluginlist *list)
00146 {
00147     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00148     cpl_plugin *plugin = &recipe->interface;
00149 
00150     cpl_plugin_init(plugin,
00151             CPL_PLUGIN_API,
00152             KMOS_BINARY_VERSION,
00153             CPL_PLUGIN_TYPE_RECIPE,
00154             "kmos_sci_red",
00155             "Reconstruct obj/sky-pairs individually and combine "
00156             "them afterwards",
00157             kmos_sci_red_description,
00158             "Alex Agudo Berbel, Yves Jung",
00159             "usd-help@eso.org",
00160             kmos_get_license(),
00161             kmos_sci_red_create,
00162             kmos_sci_red_exec,
00163             kmos_sci_red_destroy);
00164 
00165     cpl_pluginlist_append(list, plugin);
00166 
00167     return 0;
00168 }
00169 
00170 /*----------------------------------------------------------------------------*/
00178 /*----------------------------------------------------------------------------*/
00179 static int kmos_sci_red_create(cpl_plugin *plugin)
00180 {
00181     cpl_recipe *recipe;
00182     cpl_parameter *p;
00183 
00184     /* Check that the plugin is part of a valid recipe */
00185     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00186         recipe = (cpl_recipe *)plugin;
00187     else
00188         return -1;
00189 
00190     /* Create the parameters list in the cpl_recipe object */
00191     recipe->parameters = cpl_parameterlist_new();
00192 
00193     /* --imethod (interpolation method) */
00194     p = cpl_parameter_new_value("kmos.kmos_sci_red.imethod", CPL_TYPE_STRING,
00195             "Method to use for interpolation during reconstruction. "
00196             "[\"NN\" (nearest neighbour), "
00197             "\"lwNN\" (linear weighted nearest neighbor), "
00198             "\"swNN\" (square weighted nearest neighbor), "
00199             "\"MS\" (Modified Shepard's method)"
00200             "\"CS\" (Cubic spline)]",
00201             "kmos.kmos_sci_red", "CS");
00202     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00203     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00204     cpl_parameterlist_append(recipe->parameters, p);
00205 
00206     /* --smethod  (shift interpolation method) */
00207     p = cpl_parameter_new_value("kmos.kmos_sci_red.smethod", CPL_TYPE_STRING,
00208             "Method to use for interpolation during shifting. "
00209             "[\"NN\" (nearest neighbour), "
00210             "\"CS\" (Cubic spline)]",
00211             "kmos.kmos_sci_red", "CS");
00212     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "smethod");
00213     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00214     cpl_parameterlist_append(recipe->parameters, p);
00215 
00216     /* --method  (shift method) */
00217     p = cpl_parameter_new_value("kmos.kmos_sci_red.method", CPL_TYPE_STRING,
00218             "The shifting method:   "
00219             "'none': no shifting, combined directly, "
00220             "'header': shift according to WCS (default), "
00221             "'center': centering algorithm, "
00222             "'user': read shifts from file",
00223             "kmos.kmos_sci_red", "header");
00224     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
00225     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00226     cpl_parameterlist_append(recipe->parameters, p);
00227 
00228     /* --fmethod */
00229     p = cpl_parameter_new_value("kmos.kmos_sci_red.fmethod", CPL_TYPE_STRING,
00230             "The fitting method (applies only when method='center'):   "
00231             "'gauss': fit a gauss function to collapsed image (default), "
00232             "'moffat': fit a moffat function to collapsed image",
00233             "kmos.kmos_sci_red", "gauss");
00234     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00235     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00236     cpl_parameterlist_append(recipe->parameters, p);
00237 
00238     /* --name */
00239     p = cpl_parameter_new_value("kmos.kmos_sci_red.name", CPL_TYPE_STRING,
00240             "Name of the object to combine.", "kmos.kmos_sci_red", "");
00241     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00242     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00243     cpl_parameterlist_append(recipe->parameters, p);
00244 
00245     /* --ifus */
00246     p = cpl_parameter_new_value("kmos.kmos_sci_red.ifus", CPL_TYPE_STRING,
00247             "The indices of the IFUs to combine. \"ifu1;ifu2;...\"", 
00248             "kmos.kmos_sci_red", "");
00249     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00250     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00251     cpl_parameterlist_append(recipe->parameters, p);
00252 
00253     /* --pix_scale */
00254     p = cpl_parameter_new_value("kmos.kmos_sci_red.pix_scale", CPL_TYPE_DOUBLE,
00255             "Change the pixel scale [arcsec]. "
00256             "Default of 0.2\" results into cubes of 14x14pix, "
00257             "a scale of 0.1\" results into cubes of 28x28pix, etc.",
00258             "kmos.kmos_sci_red", KMOS_PIX_RESOLUTION);
00259     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
00260     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00261     cpl_parameterlist_append(recipe->parameters, p);
00262 
00263     /* --suppress_extension */
00264     p = cpl_parameter_new_value("kmos.kmos_sci_red.suppress_extension",
00265             CPL_TYPE_BOOL,
00266             "Suppress arbitrary filename extension."
00267             "(TRUE (apply) or FALSE (don't apply)",
00268             "kmos.kmos_sci_red", FALSE);
00269     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
00270     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00271     cpl_parameterlist_append(recipe->parameters, p);
00272 
00273     /* --neighborhoodRange */
00274     p = cpl_parameter_new_value("kmos.kmos_sci_red.neighborhoodRange",
00275             CPL_TYPE_DOUBLE, 
00276             "Defines the range to search for neighbors in pixels",
00277             "kmos.kmos_sci_red", 1.001);
00278     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00279     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00280     cpl_parameterlist_append(recipe->parameters, p);
00281 
00282     /* --filename */
00283     p = cpl_parameter_new_value("kmos.kmos_sci_red.filename", CPL_TYPE_STRING,
00284             "The path to the file with the shift vectors."
00285             "(Applies only to method='user')",
00286             "kmos.kmos_sci_red", "");
00287     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00288     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00289     cpl_parameterlist_append(recipe->parameters, p);
00290 
00291     /* --flux */
00292     p = cpl_parameter_new_value("kmos.kmos_sci_red.flux", CPL_TYPE_BOOL,
00293             "TRUE: Apply flux conservation. FALSE: otherwise", 
00294             "kmos.kmos_sci_red", FALSE);
00295     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00296     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00297     cpl_parameterlist_append(recipe->parameters, p);
00298 
00299     /* --background */
00300     p = cpl_parameter_new_value("kmos.kmos_sci_red.background", CPL_TYPE_BOOL, 
00301             "TRUE: Apply background removal. FALSE: otherwise",
00302             "kmos.kmos_sci_red", FALSE);
00303     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "background");
00304     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00305     cpl_parameterlist_append(recipe->parameters, p);
00306 
00307     /* --fast_mode */
00308     p = cpl_parameter_new_value("kmos.kmos_sci_red.fast_mode", CPL_TYPE_BOOL,
00309             "FALSE: cubes are shifted and combined,"
00310             "TRUE: cubes are collapsed and then shifted and combined",
00311             "kmos.kmos_sci_red", FALSE);
00312     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fast_mode");
00313     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00314     cpl_parameterlist_append(recipe->parameters, p);
00315 
00316     /* --extrapolate */
00317     p = cpl_parameter_new_value("kmos.kmos_sci_red.extrapolate", CPL_TYPE_BOOL,
00318             "Applies only to 'smethod=CS' when doing sub-pixel shifts: "
00319             "FALSE: shifted IFU will be filled with NaN's at the borders,"
00320             "TRUE: shifted IFU will be extrapolated at the borders",
00321             "kmos.kmos_sci_red", FALSE);
00322     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extrapolate");
00323     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00324     cpl_parameterlist_append(recipe->parameters, p);
00325 
00326     /* --xcal_interpolation */
00327     p = cpl_parameter_new_value("kmos.kmos_sci_red.xcal_interpolation",
00328             CPL_TYPE_BOOL,
00329             "TRUE: Interpolate xcal between rotator angles. FALSE: otherwise",
00330             "kmos.kmos_sci_red", TRUE);
00331     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcal_interpolation");
00332     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00333     cpl_parameterlist_append(recipe->parameters, p);
00334 
00335     /* --edge_nan */
00336     p = cpl_parameter_new_value("kmos.kmos_sci_red.edge_nan", CPL_TYPE_BOOL,
00337             "Set borders of cubes to NaN before combining them."
00338             "(TRUE (apply) or FALSE (don't apply)",
00339             "kmos.kmos_sci_red", FALSE);
00340     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "edge_nan");
00341     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00342     cpl_parameterlist_append(recipe->parameters, p);
00343 
00344     /* --no_combine */
00345     p = cpl_parameter_new_value("kmos.kmos_sci_red.no_combine", CPL_TYPE_BOOL,
00346             "Don't combine cubes after reconstruction."
00347             "(TRUE (apply) or FALSE (don't apply)",
00348             "kmos.kmos_sci_red", FALSE);
00349     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_combine");
00350     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00351     cpl_parameterlist_append(recipe->parameters, p);
00352 
00353     /* --no_subtract */
00354     p = cpl_parameter_new_value("kmos.kmos_sci_red.no_subtract", CPL_TYPE_BOOL,
00355             "Don't sky subtract object and references."
00356             "(TRUE (apply) or FALSE (don't apply)",
00357             "kmos.kmos_sci_red", FALSE);
00358     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_subtract");
00359     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00360     cpl_parameterlist_append(recipe->parameters, p);
00361 
00362     /* --sky_tweak */
00363     p = cpl_parameter_new_value("kmos.kmos_sci_red.sky_tweak", CPL_TYPE_BOOL,
00364             "Use modified sky cube for sky subtraction."
00365             "(TRUE (apply) or FALSE (don't apply)",
00366             "kmos.kmos_sci_red", FALSE);
00367     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_tweak");
00368     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00369     cpl_parameterlist_append(recipe->parameters, p);
00370 
00371     /* --tbsub */
00372     p = cpl_parameter_new_value("kmos.kmos_sci_red.tbsub", CPL_TYPE_BOOL,
00373             "Subtract thermal background from input cube."
00374             "(TRUE (apply) or FALSE (don't apply)",
00375             "kmos.kmos_sci_red", TRUE);
00376     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "tbsub");
00377     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00378     cpl_parameterlist_append(recipe->parameters, p);
00379 
00380     // add parameters for band-definition
00381     kmos_band_pars_create(recipe->parameters, "kmos.kmos_sci_red");
00382 
00383     /* --obj_sky_table */
00384     p = cpl_parameter_new_value("kmos.kmos_sci_red.obj_sky_table",
00385             CPL_TYPE_STRING,
00386             "The path to the file with the modified obj/sky associations.",
00387             "kmos.kmos_sci_red", "");
00388     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "obj_sky_table");
00389     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00390     cpl_parameterlist_append(recipe->parameters, p);
00391 
00392     /* --velocity_offset */
00393     p = cpl_parameter_new_value("kmos.kmos_sci_red.velocity_offset",
00394             CPL_TYPE_DOUBLE,
00395             "Specify velocity offset correction in km/s for lambda scale",
00396             "kmos.kmos_sci_red", 0.0);
00397     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "velocity_offset");
00398     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00399     cpl_parameterlist_append(recipe->parameters, p);
00400 
00401     /* --save_interims */
00402     p=cpl_parameter_new_value("kmos.kmos_sci_red.save_interims", CPL_TYPE_BOOL,
00403             "Save interim object and sky cubes. "
00404             "Can only be used together with --sky_tweak",
00405             "kmos.kmos_sci_red", FALSE);
00406     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_interims");
00407     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00408     cpl_parameterlist_append(recipe->parameters, p);
00409 
00410     /* --collapse_reconstructed */
00411     p = cpl_parameter_new_value("kmos.kmos_sci_red.collapse_reconstructed", 
00412             CPL_TYPE_BOOL, "Flag to collapse the reconstructed images", 
00413             "kmos.kmos_sci_red", FALSE);
00414     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"collapse_reconstructed");
00415     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00416     cpl_parameterlist_append(recipe->parameters, p);
00417 
00418     /* --collapse_combined */
00419     p = cpl_parameter_new_value("kmos.kmos_sci_red.collapse_combined", 
00420             CPL_TYPE_BOOL, "Flag to collapse the combined images", 
00421             "kmos.kmos_sci_red", FALSE);
00422     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "collapse_combined");
00423     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00424     cpl_parameterlist_append(recipe->parameters, p);
00425 
00426     return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_sci_red",
00427             DEF_REJ_METHOD, FALSE);
00428 }
00429 
00430 /*----------------------------------------------------------------------------*/
00436 /*----------------------------------------------------------------------------*/
00437 static int kmos_sci_red_exec(cpl_plugin *plugin)
00438 {
00439     cpl_recipe  *recipe;
00440 
00441     /* Get the recipe out of the plugin */
00442     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00443         recipe = (cpl_recipe *)plugin;
00444     else return -1 ;
00445 
00446     return kmos_sci_red(recipe->parameters, recipe->frames);
00447 }
00448 
00449 /*----------------------------------------------------------------------------*/
00455 /*----------------------------------------------------------------------------*/
00456 static int kmos_sci_red_destroy(cpl_plugin *plugin)
00457 {
00458     cpl_recipe *recipe;
00459 
00460     /* Get the recipe out of the plugin */
00461     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00462         recipe = (cpl_recipe *)plugin;
00463     else return -1 ;
00464 
00465     cpl_parameterlist_delete(recipe->parameters);
00466     return 0 ;
00467 }
00468 
00469 /*----------------------------------------------------------------------------*/
00482 /*----------------------------------------------------------------------------*/
00483 static int kmos_sci_red(cpl_parameterlist * parlist, cpl_frameset * frameset)
00484 {
00485     const cpl_parameter *   par ;
00486     /*********************/
00487     /* Parsed Parameters */
00488     int flux, background, extrapolate, fast_mode, edge_nan, no_combine, 
00489         no_subtract, sky_tweak, tbsub, xcal_interpolation, suppress_extension, 
00490         save_interims, citer, cmin, cmax, collapse_combined,
00491         collapse_reconstructed ;
00492     double neighborhoodRange, pix_scale, cpos_rej, cneg_rej,
00493            velo_offset, velo_corr ;
00494     double              *   velo_corr_ptr ;
00495     const char * imethod, * smethod, * cmethod, * comb_method, * fmethod, 
00496           * filename, * ifus_txt, * name, * fn_obj_sky_table, * fn_reconstr ;
00497     /*********************/
00498 
00499     double scaling, conversion, f_0, zpoint ;
00500     int print_once, cube_counter_data, cube_counter_noise, do_sky_subtraction,
00501         suppress_index, mapping_id, nb_science, nb_telluric, nb_illum_corr,
00502         telluric_ok, actual_msg_level, nr_data ;
00503     int i, j, jj, sf, ifu_nr, sky_ifu_nr, det_nr ;
00504     char                *   suffix ;
00505     char                *   mapping_mode ;
00506     char                *   extname ;
00507     char                *   keyword ;
00508     char                **  split ;
00509     char                *   fn_suffix ;
00510     const char          *   tmp_str ;
00511     const char          *   fn_obj ;
00512     const char          *   filter_id ;
00513     const char          *   fn_out ;
00514         
00515     /*****************************/
00516     /* TO BE CHECKED AND REMOVED */
00517     enum kmo_frame_type     ft ;
00518     char                    content[256];
00519     main_fits_desc          desc_telluric, desc1 ;
00520     int                     tmp_int, idx ;
00521     /*****************************/
00522 
00523     enum extrapolationType  extrapol_enum ;
00524     cpl_propertylist    *   header_tmp ;
00525     cpl_propertylist    *   main_header ;
00526     int                 *   qc_output_unit ;
00527     int                 *   bounds ;
00528     gridDefinition          gd ;
00529     armNameStruct       *   arm_name_struct ;
00530        
00531     cpl_polynomial      *   oh_lcorr_coeffs ;
00532     cpl_vector          *   ifus ;
00533     cpl_array           **  unused_ifus_before ;
00534     cpl_array           **  unused_ifus_after ;
00535     cpl_frame           *   sky_frame ;
00536     cpl_frame           *   sky_as_object_frame ;
00537     cpl_frame           *   ref_spectrum_frame ;
00538     cpl_frame           *   xcal_frame ;
00539     cpl_frame           *   ycal_frame ;
00540     cpl_frame           *   lcal_frame ;
00541     cpl_frame           *   flat_frame ;
00542     cpl_frame           *   telluric_frame ;
00543     cpl_frame           *   tmp_frame ;
00544         
00545     cpl_table           *   band_table ;
00546 
00547     cpl_imagelist       *   combined_data ;
00548     cpl_imagelist       *   combined_noise ;
00549     cpl_imagelist       *   tmp_cube1 ;
00550     cpl_imagelist       *   tmp_cube2 ;
00551     
00552     cpl_image           *   tmpImg ;
00553     cpl_image           *   exp_mask ;
00554     cpl_image           *   illum_data ;
00555     cpl_image           *   illum_noise ;
00556     
00557     cpl_imagelist       **  cube_data ;
00558     cpl_imagelist       **  cube_noise ;
00559     cpl_imagelist       **  cube_interim_object ;
00560     cpl_imagelist       **  cube_interim_sky  ;
00561 
00562     cpl_propertylist    **  header_data ;
00563     cpl_propertylist    **  header_noise ;
00564     cpl_propertylist    **  header_sky ;
00565 
00566     kmclipm_vector      *   telluric_data ;
00567     kmclipm_vector      *   telluric_noise ;
00568 
00569     /* Initialise */
00570     print_once = FALSE ;
00571     cube_counter_data = cube_counter_noise = 0 ; 
00572     do_sky_subtraction = FALSE ;
00573     suppress_index = 0 ;
00574     mapping_id = -1 ;
00575     combined_data = combined_noise = NULL ;
00576     sky_as_object_frame = NULL ;
00577 
00578     /* Check entries */
00579     if (parlist == NULL || frameset == NULL) {
00580         cpl_msg_error(__func__, "Null Inputs") ;
00581         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00582         return -1 ;
00583     }
00584 
00585     /* Get parameters */
00586     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.flux");
00587     flux = cpl_parameter_get_bool(par);
00588     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.background");
00589     background = cpl_parameter_get_bool(par);
00590     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.imethod");
00591     imethod = cpl_parameter_get_string(par) ;
00592     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.smethod");
00593     smethod = cpl_parameter_get_string(par) ;
00594     par = cpl_parameterlist_find_const(parlist,
00595             "kmos.kmos_sci_red.neighborhoodRange");
00596     neighborhoodRange = cpl_parameter_get_double(par) ;
00597     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.method");
00598     comb_method = cpl_parameter_get_string(par) ;
00599     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.fmethod");
00600     fmethod = cpl_parameter_get_string(par) ;
00601     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.filename");
00602     filename = cpl_parameter_get_string(par) ;
00603     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.ifus");
00604     ifus_txt = cpl_parameter_get_string(par) ;
00605     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.name");
00606     name = cpl_parameter_get_string(par) ;
00607     kmos_band_pars_load(parlist, "kmos.kmos_sci_red");
00608     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.extrapolate");
00609     extrapolate = cpl_parameter_get_bool(par);
00610     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.fast_mode");
00611     fast_mode = cpl_parameter_get_bool(par);
00612     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.edge_nan");
00613     edge_nan = cpl_parameter_get_bool(par);
00614     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_combine");
00615     no_combine = cpl_parameter_get_bool(par);
00616     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_subtract");
00617     no_subtract = cpl_parameter_get_bool(par);
00618     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.sky_tweak");
00619     sky_tweak = cpl_parameter_get_bool(par);
00620     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.tbsub");
00621     tbsub = cpl_parameter_get_bool(par);
00622     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.pix_scale");
00623     pix_scale = cpl_parameter_get_double(par) ;
00624     par = cpl_parameterlist_find_const(parlist,
00625             "kmos.kmos_sci_red.xcal_interpolation");
00626     xcal_interpolation = cpl_parameter_get_bool(par);
00627     par = cpl_parameterlist_find_const(parlist,
00628             "kmos.kmos_sci_red.suppress_extension");
00629     suppress_extension = cpl_parameter_get_bool(par);
00630     par = cpl_parameterlist_find_const(parlist, 
00631             "kmos.kmos_sci_red.obj_sky_table");
00632     fn_obj_sky_table = cpl_parameter_get_string(par) ;
00633     kmos_combine_pars_load(parlist, "kmos.kmos_sci_red", &cmethod, &cpos_rej, 
00634             &cneg_rej, &citer, &cmin, &cmax, FALSE);
00635     par = cpl_parameterlist_find_const(parlist,
00636             "kmos.kmos_sci_red.velocity_offset");
00637     velo_offset = cpl_parameter_get_double(par) ;
00638     velo_corr = 1. + velo_offset * 1000. / CPL_PHYS_C;
00639     velo_corr_ptr = &velo_corr;
00640     par = cpl_parameterlist_find_const(parlist,
00641             "kmos.kmos_sci_red.save_interims");
00642     save_interims = cpl_parameter_get_bool(par);
00643     par = cpl_parameterlist_find_const(parlist,
00644             "kmos.kmos_sci_red.collapse_combined");
00645     collapse_combined = cpl_parameter_get_bool(par);
00646     par = cpl_parameterlist_find_const(parlist,
00647             "kmos.kmos_sci_red.collapse_reconstructed");
00648     collapse_reconstructed = cpl_parameter_get_bool(par);
00649 
00650     /* Check Parameters */
00651     if (strcmp(imethod, "NN") && strcmp(imethod, "lwNN") && 
00652             strcmp(imethod, "swNN") && strcmp(imethod, "MS") && 
00653             strcmp(imethod, "CS")) {
00654         cpl_msg_error(__func__, 
00655                 "imethod must be 'NN','lwNN','swNN','MS' or 'CS'") ;
00656         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00657         return -1 ;
00658     }
00659     if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
00660         cpl_msg_error(__func__, 
00661                 "smethod must be 'NN' or 'CS'") ;
00662         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00663         return -1 ;
00664     }
00665     if (neighborhoodRange <= 0.0) {
00666         cpl_msg_error(__func__, 
00667                 "neighborhoodRange must be greater than 0.0") ;
00668         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00669         return -1 ;
00670     }
00671     if (strcmp(comb_method, "none") && strcmp(comb_method, "header") &&
00672             strcmp(comb_method, "center") && strcmp(comb_method, "user")) {
00673         cpl_msg_error(__func__, 
00674             "shift methods must be 'none', 'header', 'center' or 'user'") ;
00675         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00676         return -1 ;
00677     }
00678     if (strcmp(ifus_txt, "") && strcmp(name, "")) {
00679         cpl_msg_error(__func__, 
00680                 "name and IFU indices cannot be both provided") ;
00681         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00682         return -1 ;
00683     }
00684     if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
00685         cpl_msg_error(__func__, "smethod must be 'NN' or 'CS'") ;
00686         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00687         return -1 ;
00688     }
00689     if (!strcmp(smethod, "NN") && extrapolate == TRUE) {
00690         cpl_msg_error(__func__,
00691                 "extrapolation in not compatible with smethod 'NN'");
00692         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00693         return -1 ;
00694     }
00695     if (!strcmp(smethod, "CS")) smethod = "BCS";
00696     if (!strcmp(smethod, "BCS") && extrapolate == TRUE) 
00697         extrapol_enum = BCS_NATURAL;
00698     else
00699         extrapol_enum = NONE_NANS;
00700 
00701     if (no_subtract && sky_tweak) {
00702         cpl_msg_error(__func__,"no_subtract and sky_tweak cannot be both TRUE");
00703         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00704         return -1 ;
00705     }
00706     if (pix_scale < 0.01 || pix_scale > 0.4) {
00707         cpl_msg_error(__func__, "pix_scale must be between 0.01 and 0.4");
00708         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00709         return -1 ;
00710     }
00711  
00712     if (cpl_frameset_count_tags(frameset, SCIENCE) == 1 || no_subtract) {
00713         no_combine = TRUE;
00714         cpl_msg_info(__func__, 
00715                 "--no_combine set to TRUE (1 SCIENCE frame or --no_subtract");
00716     }
00717 
00718     /* Identify the RAW and CALIB frames in the input frameset */
00719     if (kmo_dfs_set_groups(frameset, "kmos_sci_red") != 1) {
00720         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00721         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00722         return -1 ;
00723     }
00724     
00725     /* Check the inputs consistency */
00726     if (kmos_sci_red_check_inputs(frameset, &mapping_id) != 1) {
00727         cpl_msg_error(__func__, "Input frameset is not consistent") ;
00728         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00729         return -1 ;
00730     }
00731     if (mapping_id == 0)    mapping_mode = NULL ;
00732     if (mapping_id == 1)    mapping_mode = "mapping8" ;
00733     if (mapping_id == 2)    mapping_mode = "mapping24" ;
00734 
00735     /* Instrument setup */
00736     suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,SCIENCE),TRUE,FALSE);
00737     cpl_msg_info(__func__, "Detected instrument setup:   %s", suffix+1);
00738     cpl_free(suffix); 
00739  
00740     /* Load IFUS if specified */
00741     if (strcmp(ifus_txt, "")) {
00742         nb_science = cpl_frameset_count_tags(frameset, SCIENCE);
00743         ifus = kmo_identify_values(ifus_txt);
00744         if (ifus == NULL || cpl_vector_get_size(ifus) != nb_science) {
00745             if (ifus != NULL) cpl_vector_delete(ifus);
00746             cpl_msg_error(__func__, "ifus size must match the science frames") ;
00747             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00748             return -1 ;
00749         }
00750     } else {
00751         ifus = NULL ;
00752     }
00753 
00754     /* Mapping mode */
00755     if (mapping_id > 0) {
00756         if ((ifus != NULL) || (strcmp(name, ""))) {
00757             cpl_msg_warning(__func__,"Mapping Mode ٍ+ Specific IFUs requested") ;
00758         } else {
00759             if (!strcmp(smethod, "BCS")) {
00760                 extrapol_enum = BCS_NATURAL;
00761                 cpl_msg_info(__func__, "Mapping Mode : extrapolation set") ;
00762             }
00763         }
00764     }
00765 
00766     /* Check which IFUs are active for all frames */
00767     unused_ifus_before = kmo_get_unused_ifus(frameset, 1, 1);
00768     unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
00769     kmo_print_unused_ifus(unused_ifus_before, FALSE);
00770     kmo_free_unused_ifus(unused_ifus_before);
00771 
00772     /* Setup grid definition, wavelength start and end are set later */
00773     kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.);
00774 
00775     /* Get frames */
00776     xcal_frame = kmo_dfs_get_frame(frameset, XCAL) ;
00777     ycal_frame = kmo_dfs_get_frame(frameset, YCAL) ;
00778     lcal_frame = kmo_dfs_get_frame(frameset, LCAL) ;
00779     flat_frame = kmo_dfs_get_frame(frameset, MASTER_FLAT) ;
00780     ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC) ;
00781     nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
00782 
00783     /* Get left and right bounds of IFUs from XCAL */
00784     header_tmp = kmo_dfs_load_primary_header(frameset, XCAL);
00785     bounds = kmclipm_extract_bounds(header_tmp);
00786     cpl_propertylist_delete(header_tmp);
00787     if (bounds == NULL) {
00788         if (ifus != NULL) cpl_vector_delete(ifus);
00789         kmo_free_unused_ifus(unused_ifus_after);
00790         cpl_msg_error(__func__, "Cannot compute bounds") ;
00791         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00792         return -1 ;
00793     }
00794 
00795     /* armNameStruct: objects that need to be reconstructed and their 
00796        associated sky. Valid STD frames with objects and associated sky.
00797        Get valid object names, either one object name in several frames, 
00798        or all object names */
00799     if (!strcmp(fn_obj_sky_table, "")) {
00800         arm_name_struct = kmo_create_armNameStruct(frameset, SCIENCE, ifus,
00801                 name, unused_ifus_after, bounds, mapping_mode, no_subtract);
00802         /* TODO : need to save ?? */
00803         kmo_save_objSkyStruct(arm_name_struct->obj_sky_struct);
00804     } else {
00805         // read in obj/sky-table
00806         objSkyStruct *obj_sky_struct = NULL;
00807         obj_sky_struct = kmo_read_objSkyStruct(fn_obj_sky_table, frameset, 
00808                 SCIENCE);
00809 
00810         /* Check if any sky-IFUs have been specified not beeing the */
00811         /* same IFU# for objects. */
00812         // In this case sky_tweak must be activated
00813         for (i = 0; i < obj_sky_struct->size; i++) {
00814             if (obj_sky_struct->table[i].objFrame != NULL) {
00815                 for (j = 0; j < KMOS_NR_IFUS; j++) {
00816                     if ((obj_sky_struct->table[i].skyIfus[j] > 0) && 
00817                             (sky_tweak == FALSE)) {
00818                         kmo_print_objSkyStruct(obj_sky_struct);
00819                         kmo_delete_objSkyStruct(obj_sky_struct);
00820                         cpl_msg_error(__func__, 
00821             "--sky_tweak needs to be set when sky are used from other IFUs");
00822                         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00823                         return -1 ;
00824                     }
00825                 }
00826             }
00827         }
00828         arm_name_struct = kmo_create_armNameStruct2(obj_sky_struct, frameset, 
00829                 SCIENCE, ifus, name, unused_ifus_after, bounds, mapping_mode, 
00830                 no_subtract);
00831     }
00832     if (ifus != NULL) cpl_vector_delete(ifus);
00833     if (arm_name_struct == NULL) {
00834         kmo_free_unused_ifus(unused_ifus_after);
00835         cpl_free(bounds);
00836         cpl_msg_error(__func__, "Cannot compute ARM/name structure") ;
00837         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00838         return -1 ;
00839     }
00840     kmo_print_armNameStruct(frameset, arm_name_struct);
00841     
00842     /* Check Telluric availability for each Object */
00843     /* in mapping-mode check if for all IFUs there is either no  */
00844     /* telluric at all or the same number of tellurics than object names */
00845     nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
00846     if (nb_telluric > 0 && mapping_id > 0) {
00847         for (i = 0; i < arm_name_struct->nrNames; i++) {
00848             if (arm_name_struct->telluricCnt[i] =! arm_name_struct->namesCnt[i]
00849                  && (arm_name_struct->telluricCnt[i] =! 0)) {
00850                 cpl_msg_error(__func__, "Mosaics need a TELLURIC per detector");
00851                 cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE) ;
00852                 return -1 ;
00853             }
00854         }
00855     }
00856 
00857     /* Allocate data */
00858     cube_data=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, sizeof(cpl_imagelist*));
00859     cube_noise=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS,sizeof(cpl_imagelist*));
00860     header_data = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00861             sizeof(cpl_propertylist*));
00862     header_noise = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00863             sizeof(cpl_propertylist*));
00864     if (save_interims) {
00865         cube_interim_object=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, 
00866                 sizeof(cpl_imagelist*));
00867         cube_interim_sky =(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, 
00868                 sizeof(cpl_imagelist*));
00869         header_sky = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00870                 sizeof(cpl_propertylist*));
00871     }
00872 
00873     /* Loop all science frames containing at least one object */
00874     cpl_msg_info(__func__, "Reconstructing & saving cubes with objects");
00875     for (sf = 0; sf < arm_name_struct->size; sf++) {
00876         fn_obj = cpl_frame_get_filename(
00877                 arm_name_struct->obj_sky_struct->table[sf].objFrame);
00878         if ((main_header = kmclipm_propertylist_load(fn_obj, 0)) == NULL) {
00879             kmo_free_unused_ifus(unused_ifus_after);
00880             cpl_free(bounds);
00881             kmo_delete_armNameStruct(arm_name_struct);
00882             cpl_free(qc_output_unit) ;
00883             cpl_free(cube_data) ;
00884             cpl_free(cube_noise) ;
00885             cpl_free(header_data) ;
00886             cpl_free(header_noise) ;
00887             if (save_interims) {
00888                 cpl_free(cube_interim_object) ;
00889                 cpl_free(cube_interim_sky) ;
00890                 cpl_free(header_sky) ;
00891             }
00892             cpl_msg_error(__func__, "Cannot Load main header");
00893             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00894             return -1 ;
00895         }
00896         actual_msg_level = cpl_msg_get_level();
00897 
00898         /* Hold the QC parameter */
00899         qc_output_unit = cpl_calloc(KMOS_NR_IFUS, sizeof(int)) ;
00900 
00901         /* Reconstruct science frame */
00902         cpl_msg_info(__func__, "   > processing frame: %s", fn_obj);
00903         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
00904 
00905             /* Initialise */
00906             cube_data[ifu_nr-1] = cube_noise[ifu_nr-1] = NULL ; 
00907 
00908             sky_ifu_nr = ifu_nr;
00909             det_nr = (ifu_nr - 1)/KMOS_IFUS_PER_DETECTOR + 1;
00910 
00911             /* Get subheader data */
00912             header_data[ifu_nr-1] = kmclipm_propertylist_load(fn_obj, det_nr);
00913             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
00914             kmclipm_update_property_string(header_data[ifu_nr-1],
00915                     EXTNAME, extname, "FITS extension name");
00916             cpl_free(extname);
00917 
00918             if (arm_name_struct->name_ids[ifu_nr-1+sf*KMOS_NR_IFUS] >= 1) {
00919                 // IFU is valid
00920 
00921                 /* Fill sky_as_object_frame, do_sky_subtraction and sky_frame */
00922                 sky_as_object_frame = NULL ;
00923                 if ((arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1] != NO_CORRESPONDING_SKYFRAME) && !no_subtract) {
00924                     do_sky_subtraction = TRUE;
00925                     if (no_subtract)    sky_frame = NULL;
00926                     else                sky_frame = 
00927                 arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1];
00928 
00929                     if (sky_tweak){
00930                         sky_as_object_frame = sky_frame;
00931                         sky_frame = NULL;
00932                         sky_ifu_nr = arm_name_struct->obj_sky_struct->table[sf].skyIfus[ifu_nr-1];
00933                     }
00934                 } else {
00935                     do_sky_subtraction = FALSE;
00936                     sky_frame = NULL;
00937                 }
00938 
00939                 /* Get filter and setup grid definition using WAVE_BAND */
00940                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, det_nr, 
00941                         IFU_FILTID_POSTFIX);
00942                 filter_id = cpl_propertylist_get_string(main_header, keyword);
00943                 cpl_free(keyword); 
00944 
00945                 if (print_once) cpl_msg_set_level(CPL_MSG_WARNING);
00946                 print_once = TRUE;
00947 
00948                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0);
00949                 kmclipm_setup_grid_band_lcal(&gd, filter_id, band_table);
00950                 cpl_table_delete(band_table);
00951 
00952                 cpl_msg_set_level(actual_msg_level);
00953 
00954                 /* calc WCS & update subheader */
00955                 kmo_calc_wcs_gd(main_header, header_data[ifu_nr-1], ifu_nr, gd);
00956 
00957                 /* Update some keywords  */
00958                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS, 3, 
00959                         "number of data axes");
00960                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS1, 
00961                         gd.x.dim, "length of data axis 1");
00962                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS2, 
00963                         gd.y.dim, "length of data axis 2");
00964                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS3, 
00965                         gd.l.dim, "length of data axis 3");
00966 
00967                 /* Option save_interim only applies if sky_tweak is used */
00968                 if (save_interims && sky_as_object_frame != NULL) {
00969                     header_tmp = kmclipm_propertylist_load(
00970                             cpl_frame_get_filename(sky_as_object_frame), 0);
00971                             
00972                     header_sky[ifu_nr-1]=kmclipm_propertylist_load(
00973                             cpl_frame_get_filename(sky_as_object_frame),det_nr);
00974                     extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
00975                     kmclipm_update_property_string(header_sky[ifu_nr-1], 
00976                             EXTNAME, extname, "FITS extension name");
00977                     cpl_free(extname);
00978 
00979                     kmo_calc_wcs_gd(header_tmp, header_sky[ifu_nr-1], 
00980                             ifu_nr, gd);
00981                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS, 3,
00982                             "number of data axes");
00983                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS1, 
00984                             gd.x.dim, "length of data axis 1");
00985                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS2, 
00986                             gd.y.dim, "length of data axis 2");
00987                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS3, 
00988                             gd.l.dim, "length of data axis 3");
00989                     cpl_propertylist_delete(header_tmp); 
00990                 }
00991 
00992                 /* OH lines based lambda correction */
00993                 oh_lcorr_coeffs = NULL ;
00994                 if (ref_spectrum_frame != NULL) {
00995                     if (kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
00996                             bounds[2*(ifu_nr-1)+1],
00997                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
00998                             SCIENCE, NULL, NULL, flat_frame, xcal_frame,
00999                             ycal_frame, lcal_frame, NULL, NULL, &gd, &tmp_cube1,
01000                             &tmp_cube2, FALSE, FALSE,
01001                             xcal_interpolation) == CPL_ERROR_NONE) {
01002                         oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1, 
01003                                 header_data[ifu_nr-1], ref_spectrum_frame, gd,
01004                                 filter_id, ifu_nr);
01005                         cpl_imagelist_delete(tmp_cube1); 
01006                         cpl_imagelist_delete(tmp_cube2); 
01007                     }
01008                 }
01009 
01010                 /* Reconstruct object */
01011                 kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
01012                         bounds[2*(ifu_nr-1)+1],
01013                         arm_name_struct->obj_sky_struct->table[sf].objFrame,
01014                         SCIENCE, sky_frame, SCIENCE, flat_frame, xcal_frame,
01015                         ycal_frame, lcal_frame, oh_lcorr_coeffs, velo_corr_ptr,
01016                         &gd, &cube_data[ifu_nr-1], &cube_noise[ifu_nr-1], flux,
01017                         background, xcal_interpolation);
01018                         
01019                 if (oh_lcorr_coeffs != NULL) 
01020                     cpl_polynomial_delete(oh_lcorr_coeffs); 
01021 
01022                 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01023                     kmo_free_unused_ifus(unused_ifus_after);
01024                     cpl_free(bounds);
01025                     kmo_delete_armNameStruct(arm_name_struct);
01026                     for (j=0 ; j<ifu_nr-1  ; j++) {
01027                         if (cube_data[j] != NULL) 
01028                             cpl_imagelist_delete(cube_data[j]); 
01029                         if (cube_noise[j] != NULL) 
01030                             cpl_imagelist_delete(cube_noise[j]);
01031                         cpl_propertylist_delete(header_data[j]);
01032                         cpl_propertylist_delete(header_noise[j]);
01033                         if (save_interims) {
01034                             cpl_imagelist_delete(cube_interim_object[j]);
01035                             cpl_imagelist_delete(cube_interim_sky[j]);
01036                             cpl_propertylist_delete(header_sky[j]);
01037                         }
01038                     }
01039                     cpl_propertylist_delete(header_data[ifu_nr-1]);
01040                     cpl_free(cube_data) ;
01041                     cpl_free(cube_noise) ;
01042                     cpl_free(header_data) ;
01043                     cpl_free(header_noise) ;
01044                     if (save_interims) {
01045                         cpl_free(cube_interim_object) ;
01046                         cpl_free(cube_interim_sky) ;
01047                         cpl_free(header_sky) ;
01048                     }
01049                     cpl_msg_error(__func__, "Cannot reconstruct");
01050                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01051                     return -1 ;
01052                 }
01053 
01054                 /* If sky_tweak is set, reconstruct sky frame as object */
01055                 /* use kmos_priv_sky_tweak to subtract a modified sky cube */
01056                 if (do_sky_subtraction && sky_tweak) {
01057 
01058                     /* OH lines based lambda correction */
01059                     oh_lcorr_coeffs = NULL ;
01060                     if (ref_spectrum_frame != NULL) {
01061                         if (kmo_reconstruct_sci(sky_ifu_nr,
01062                                     bounds[2*(sky_ifu_nr-1)],
01063                                     bounds[2*(sky_ifu_nr-1)+1], 
01064                                     sky_as_object_frame, SCIENCE, NULL, NULL, 
01065                                     flat_frame, xcal_frame, ycal_frame, 
01066                                     lcal_frame, NULL, NULL, &gd, &tmp_cube1, 
01067                                     &tmp_cube2, FALSE, FALSE, 
01068                                     xcal_interpolation) == CPL_ERROR_NONE) {
01069                             oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1,
01070                                     header_data[ifu_nr-1], ref_spectrum_frame, 
01071                                     gd, filter_id, ifu_nr);
01072                             cpl_imagelist_delete(tmp_cube1);
01073                             cpl_imagelist_delete(tmp_cube2); 
01074                         }
01075                     }
01076 
01077                     /* Reconstruct object */
01078                     kmo_reconstruct_sci(sky_ifu_nr, 
01079                             bounds[2*(sky_ifu_nr-1)], 
01080                             bounds[2*(sky_ifu_nr-1)+1], sky_as_object_frame,
01081                             SCIENCE, sky_frame, SCIENCE, flat_frame,
01082                             xcal_frame, ycal_frame, lcal_frame, oh_lcorr_coeffs,
01083                             velo_corr_ptr, &gd, &tmp_cube1, &tmp_cube2,
01084                             flux, background, xcal_interpolation);
01085                             
01086                     cpl_imagelist_delete(tmp_cube2); 
01087                     if (oh_lcorr_coeffs != NULL) 
01088                         cpl_polynomial_delete(oh_lcorr_coeffs);
01089                    
01090                     if (save_interims && (sky_as_object_frame != NULL)) {
01091                         cube_interim_object[ifu_nr-1]=
01092                             cpl_imagelist_duplicate(cube_data[ifu_nr-1]);
01093                         cube_interim_sky[ifu_nr-1]=
01094                             cpl_imagelist_duplicate(tmp_cube1);
01095                     }
01096 
01097                     /* Apply the SKY tweaking */
01098                     tmp_cube2 = kmos_priv_sky_tweak(cube_data[ifu_nr-1], 
01099                             tmp_cube1,header_data[ifu_nr-1], .3, tbsub, ifu_nr);
01100                     cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01101                     cpl_imagelist_delete(tmp_cube1); 
01102                     cube_data[ifu_nr-1] = tmp_cube2 ;
01103                 } 
01104 
01105                 /* Maintain flux constant in case the pixscale is diff */
01106                 /* For example, pixscale=0.1 => images 28x28 => scaling=4 */
01107                 tmpImg = cpl_imagelist_get(cube_data[ifu_nr-1], 0);
01108                 scaling = (cpl_image_get_size_x(tmpImg) *
01109                         cpl_image_get_size_y(tmpImg)) / 
01110                     (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01111                 cpl_imagelist_divide_scalar(cube_data[ifu_nr-1], scaling);
01112                 if (cube_noise[ifu_nr-1] != NULL) {
01113                     cpl_imagelist_divide_scalar(cube_noise[ifu_nr-1], scaling);
01114                 }
01115 
01116                 /* Divide cube by telluric correction */
01117                 qc_output_unit[ifu_nr-1] = 0 ;
01118                 if (nb_telluric > 0) {
01119                     /* Create the mapping string */
01120                     if (mapping_id == 0) {
01121                         /* Get object name */
01122                         keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX, 
01123                                 ifu_nr, IFU_NAME_POSTFIX);
01124                         tmp_str = cpl_propertylist_get_string(
01125                                 header_data[ifu_nr-1], keyword);
01126                         cpl_free(keyword);
01127                     } else if (mapping_id == 1) {
01128                         tmp_str = "mapping8";
01129                     } else if (mapping_id == 2) {
01130                         tmp_str = "mapping24";
01131                     }
01132 
01133                     /* Check if the nb of occurences of the object name  */
01134                     /* is the same as the number of found tellurics for */
01135                     /* this object (which can be on different arms) */
01136                     telluric_ok = FALSE;
01137                     for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01138                         if ((!strcmp(arm_name_struct->names[jj], tmp_str) ||
01139                      !strcmp(arm_name_struct->names[jj], IFUS_USER_DEFINED)) &&
01140             arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj]) {
01141                             telluric_ok = TRUE;
01142                             break;
01143                         }
01144                     }
01145 
01146                     if (telluric_ok) {
01147                         telluric_data = kmo_tweak_load_telluric(frameset,
01148                                 ifu_nr, FALSE, no_subtract);
01149                         if (telluric_data != NULL) {
01150                             telluric_frame=kmo_dfs_get_frame(frameset,TELLURIC);
01151                             kmo_init_fits_desc(&desc_telluric);
01152                             desc_telluric=kmo_identify_fits_header(
01153                                     cpl_frame_get_filename(telluric_frame));
01154 
01155                             /* Get the index of the telluric noise */
01156                             idx = kmo_identify_index_desc(desc_telluric,
01157                                     ifu_nr, TRUE);
01158                             if (desc_telluric.sub_desc[idx-1].valid_data) {
01159                                 /* Load noise if present */
01160                                 telluric_noise = kmo_tweak_load_telluric(
01161                                         frameset,ifu_nr, TRUE, no_subtract);
01162                             } else {
01163                                 telluric_noise = NULL ;
01164                             }
01165                             kmo_free_fits_desc(&desc_telluric);
01166 
01167                             kmo_arithmetic_3D_1D(cube_data[ifu_nr-1], 
01168                                     telluric_data, cube_noise[ifu_nr-1],
01169                                     telluric_noise, "/");
01170                             if (telluric_noise != NULL) 
01171                                 kmclipm_vector_delete(telluric_noise);
01172                             kmclipm_vector_delete(telluric_data);
01173 
01174                             /* Convert to ERG if zpoint available */
01175                             zpoint = kmos_sci_red_get_zpoint(telluric_frame,
01176                                     ifu_nr) ;
01177                             if (zpoint > 0.0) {
01178                                 f_0 = kmos_sci_red_get_f0(filter_id, gd.l.dim,
01179                                         gd.l.start, gd.l.delta) ; 
01180                                 if (f_0 > 0.0) {
01181                                     conversion = f_0*pow(10,-0.4*zpoint)/10.0 ;
01182                                     cpl_msg_info(__func__, 
01183                                 "Apply Unit conversion factor %g for IFU nb %d",
01184                                             conversion, ifu_nr) ;
01185                                     kmo_arithmetic_3D_scalar(
01186                                             cube_data[ifu_nr-1], conversion, 
01187                                             cube_noise[ifu_nr-1], "*") ;
01188                                     qc_output_unit[ifu_nr-1] = 1 ;
01189                                 }
01190                             }
01191                         }
01192                     }
01193                 }
01194 
01195                 /* Divide cube by illumination correction */
01196                 if (nb_illum_corr > 0) {
01197                     illum_data = kmo_dfs_load_image(frameset, ILLUM_CORR,
01198                             ifu_nr, FALSE, FALSE, NULL);
01199                     illum_noise = kmo_dfs_load_image(frameset, ILLUM_CORR, 
01200                             ifu_nr, TRUE, FALSE, NULL);
01201                     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01202                         cpl_msg_warning(__func__,
01203                         "No illumination correction for IFU %d available! "
01204                                         "Proceeding anyway.", ifu_nr);
01205                         if (illum_data != NULL) cpl_image_delete(illum_data);
01206                         if (illum_noise != NULL) cpl_image_delete(illum_noise);
01207                         cpl_error_reset();
01208                     } else {
01209                         kmo_arithmetic_3D_2D(cube_data[ifu_nr-1], illum_data,
01210                                 cube_noise[ifu_nr-1], illum_noise, "/");
01211                         cpl_image_delete(illum_data); 
01212                         cpl_image_delete(illum_noise);
01213                     }
01214                 }
01215             }
01216 
01217             /* Duplicate subheader data */
01218             header_noise[ifu_nr-1] = cpl_propertylist_duplicate(
01219                     header_data[ifu_nr-1]);
01220             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
01221             kmclipm_update_property_string(header_noise[ifu_nr-1], EXTNAME, 
01222                     extname, "FITS extension name");
01223             cpl_free(extname);
01224         } 
01225         cpl_propertylist_delete(main_header) ;
01226 
01227         /* Count number of reconstructed data- and noise-cubes */
01228         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01229             if (cube_data[ifu_nr-1] != NULL)    cube_counter_data++;
01230             if (cube_noise[ifu_nr-1] != NULL)   cube_counter_noise++;
01231         }
01232 
01233         /* Save reconstructed cubes of science frame */
01234         if (cube_counter_data > 0) {
01235             cpl_msg_info(__func__, "   > saving...");
01236 
01237             if (!suppress_extension) {
01238                 fn_out = fn_obj;
01239 
01240                 int nr_found = 0;
01241                 // remove any path-elements from filename and use it as suffix
01242                 split = kmo_strsplit(fn_out, "/", &nr_found);
01243                 fn_suffix = cpl_sprintf("_%s", split[nr_found-1]);
01244                 kmo_strfreev(split);
01245 
01246                 // remove '.fits' at the end if there is any
01247                 char *fff = fn_suffix;
01248                 fff += strlen(fn_suffix)-5;
01249                 if (strcmp(fff, ".fits") == 0) {
01250                     fn_suffix[strlen(fn_suffix)-5] = '\0';
01251                 }
01252             } else {
01253                 fn_suffix = cpl_sprintf("_%d", suppress_index++);
01254             }
01255 
01256             fn_out = RECONSTRUCTED_CUBE;
01257 
01258             /* Create Primary Header */
01259             kmo_dfs_save_main_header(frameset, fn_out, fn_suffix,
01260                     arm_name_struct->obj_sky_struct->table[sf].objFrame, NULL,
01261                     parlist, cpl_func);
01262             /* save intermediate products (only in sky tweak case) */
01263             if (save_interims && (sky_as_object_frame != NULL)) {
01264                 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_CUBE, 
01265                         fn_suffix,
01266                         arm_name_struct->obj_sky_struct->table[sf].objFrame, 
01267                         NULL, parlist, cpl_func);
01268                 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_SKY, 
01269                         fn_suffix,
01270                         arm_name_struct->obj_sky_struct->table[sf].objFrame,
01271                         NULL, parlist, cpl_func);
01272             }
01273 
01274             /* Loop on IFUs */
01275             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01276                 
01277                 /* Hold the QC */
01278                 if (qc_output_unit[ifu_nr-1] == 0) 
01279                     kmclipm_update_property_string(header_data[ifu_nr-1], 
01280                             "ESO QC CUBE_UNIT", "ADU/sec", "Cube Unit");
01281                 else 
01282                     kmclipm_update_property_string(header_data[ifu_nr-1], 
01283                             "ESO QC CUBE_UNIT", "ERG/sec/cm2/A", "Cube Unit");
01284 
01285                 /* Save data Extension */
01286                 kmo_dfs_save_cube(cube_data[ifu_nr-1], fn_out, fn_suffix, 
01287                         header_data[ifu_nr-1], 0./0.);
01288                 cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01289 
01290                 /* Save noise Extension */
01291                 if (cube_counter_noise > 0) {
01292                     kmo_dfs_save_cube(cube_noise[ifu_nr-1], fn_out, fn_suffix,
01293                             header_noise[ifu_nr-1], 0./0.);
01294                 }
01295                 cpl_propertylist_delete(header_noise[ifu_nr-1]);
01296                 cpl_imagelist_delete(cube_noise[ifu_nr-1]);
01297 
01298                 /* save intermediate products (only in sky tweak case */
01299                 if (save_interims && (sky_as_object_frame != NULL)) {
01300                     kmo_dfs_save_cube(cube_interim_object[ifu_nr-1],
01301                             INTERIM_OBJECT_CUBE, fn_suffix,
01302                             header_data[ifu_nr-1], 0./0.);
01303                     kmo_dfs_save_cube(cube_interim_sky[ifu_nr-1], 
01304                             INTERIM_OBJECT_SKY, fn_suffix, header_sky[ifu_nr-1],
01305                             0./0.);
01306                 }
01307                 cpl_propertylist_delete(header_data[ifu_nr-1]);
01308                 if (save_interims) {
01309                     cpl_imagelist_delete(cube_interim_object[ifu_nr-1]);
01310                     cpl_imagelist_delete(cube_interim_sky[ifu_nr-1]);
01311                     cpl_propertylist_delete(header_sky[ifu_nr-1]);
01312                 }
01313             } 
01314             cpl_free(fn_suffix);
01315         } else {
01316             cpl_msg_info(__func__, "   > all IFUs invalid, don't save");
01317             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01318                 cpl_propertylist_delete(header_data[ifu_nr-1]); 
01319                 cpl_propertylist_delete(header_noise[ifu_nr-1]); 
01320             }
01321         }
01322         cpl_free(qc_output_unit) ;
01323     } 
01324     cpl_free(bounds) ;
01325     cpl_free(cube_data);  
01326     cpl_free(cube_noise);
01327     cpl_free(header_data); 
01328     cpl_free(header_noise); 
01329     if (save_interims) {
01330         cpl_free(cube_interim_object);  
01331         cpl_free(cube_interim_sky);     
01332         cpl_free(header_sky);          
01333     }
01334 
01335     kmo_print_unused_ifus(unused_ifus_after, TRUE);
01336     kmo_free_unused_ifus(unused_ifus_after);
01337 
01338     /* Combine */
01339     suppress_index = 0;
01340     if (!no_combine) {
01341         cpl_msg_info(__func__, "Combining reconstructed objects");
01342         if (mapping_id==0 || (mapping_id>0 && (strcmp(ifus_txt, "") || 
01343                         strcmp(name,"")))){
01344             /* Loop all available objects */
01345             for (i = 0; i < arm_name_struct->nrNames; i++) {
01346                 cpl_msg_info(__func__, 
01347                         "   > object: %s", arm_name_struct->names[i]);
01348                 nr_data = arm_name_struct->namesCnt[i];
01349                 cube_data=(cpl_imagelist**)cpl_calloc(nr_data, 
01350                         sizeof(cpl_imagelist*));
01351                 cube_noise=(cpl_imagelist**)cpl_calloc(nr_data, 
01352                         sizeof(cpl_imagelist*));
01353                 header_data=(cpl_propertylist**)cpl_calloc(nr_data,
01354                         sizeof(cpl_propertylist*));
01355                 header_noise=(cpl_propertylist**)cpl_calloc(nr_data,
01356                         sizeof(cpl_propertylist*));
01357 
01358                 /* Initialise */
01359                 for (jj = 0; jj < nr_data; jj++) {
01360                     cube_data[jj] = NULL ; 
01361                     cube_noise[jj] = NULL ; 
01362                     header_data[jj] = NULL ; 
01363                     header_noise[jj] = NULL ; 
01364                 }
01365 
01366                 // setup cube-list and header-list for kmo_priv_combine()
01367                 cube_counter_data = 0;
01368                 cube_counter_noise = 0;
01369                 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01370                 while (tmp_frame != NULL ) {
01371                     fn_reconstr = cpl_frame_get_filename(tmp_frame);
01372                     main_header = kmclipm_propertylist_load(fn_reconstr, 0);
01373                     
01374                     kmo_init_fits_desc(&desc1);
01375                     desc1 = kmo_identify_fits_header(fn_reconstr);
01376 
01377                    for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01378                         // check if object-name equals the one in our list
01379                         keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX, ifu_nr,
01380                                 IFU_NAME_POSTFIX);
01381                         tmp_str=cpl_propertylist_get_string(main_header,
01382                                 keyword);
01383                         cpl_free(keyword);
01384 
01385                         if (!strcmp(arm_name_struct->names[i],tmp_str) || 
01386                         !strcmp(arm_name_struct->names[i], IFUS_USER_DEFINED)) {
01387                             /* Found object-IFU with matching name */
01388                             /* Load data & subheader */
01389                             idx=kmo_identify_index(fn_reconstr,ifu_nr,FALSE);
01390 
01391                             if (desc1.sub_desc[idx-1].valid_data) {
01392                                 cube_data[cube_counter_data] =
01393                                     kmclipm_imagelist_load(fn_reconstr,
01394                                             CPL_TYPE_FLOAT, idx);
01395     /* Set cubes borders (1 pixel) to Nan to avoid jumps in combined cube */
01396                                 if (edge_nan) {
01397                                     kmo_edge_nan(cube_data[cube_counter_data], 
01398                                             ifu_nr);
01399                                 }
01400 
01401                                 header_data[cube_counter_data] =
01402                                     kmclipm_propertylist_load(fn_reconstr, 
01403                                             idx);
01404                                 cpl_propertylist_update_string(
01405                                         header_data[cube_counter_data],
01406                                         "ESO PRO FRNAME", fn_reconstr);
01407                                 cpl_propertylist_update_int(
01408                                         header_data[cube_counter_data],
01409                                         "ESO PRO IFUNR", ifu_nr);
01410                                 cube_counter_data++;
01411                             }
01412 
01413                             /* Load noise & subheader (if existing) */
01414                             if (desc1.ex_noise) {
01415                                 idx = kmo_identify_index(fn_reconstr, ifu_nr, 
01416                                         TRUE);
01417                                 if (desc1.sub_desc[idx-1].valid_data) {
01418                                     cube_noise[cube_counter_noise] =
01419                                         kmclipm_imagelist_load(fn_reconstr, 
01420                                                 CPL_TYPE_FLOAT, idx);
01421                                     if (edge_nan) {
01422                                         kmo_edge_nan(
01423                                                 cube_noise[cube_counter_noise],
01424                                                 ifu_nr);
01425                                     }
01426                                     header_noise[cube_counter_noise] =
01427                                         kmclipm_propertylist_load(fn_reconstr, 
01428                                                 idx);
01429                                     cube_counter_noise++;
01430                                 }
01431                             }
01432                             cpl_error_reset();
01433                         }
01434                     }
01435                     kmo_free_fits_desc(&desc1);
01436                     cpl_propertylist_delete(main_header);
01437                     tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01438                 } 
01439 
01440                 if (cube_counter_noise == 0) {
01441                     cpl_free(cube_noise);
01442                     cube_noise = NULL ; 
01443                 }
01444 
01445                 if (cube_counter_data > 1) {
01446                     if (cube_counter_data == cube_counter_noise ||
01447                             cube_counter_noise == 0) {
01448                         kmo_priv_combine(cube_data, cube_noise, header_data,
01449                                 header_noise, cube_counter_data,
01450                                 cube_counter_noise, arm_name_struct->names[i],
01451                                 "", comb_method, smethod, fmethod, filename,
01452                                 cmethod, cpos_rej, cneg_rej, citer, cmin, cmax,
01453                                 extrapol_enum, flux, &combined_data,
01454                                 &combined_noise, &exp_mask);
01455                     } else {
01456                         cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
01457                         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01458                         return -1 ;
01459                     }
01460                 } else if (cube_counter_data == 1) {
01461                     cpl_msg_warning(__func__, 
01462                             "Only one reconstructed cube with this object");
01463                     combined_data = cpl_imagelist_duplicate(cube_data[0]);
01464                     tmpImg = cpl_imagelist_get(combined_data, 0);
01465                     exp_mask = cpl_image_new(cpl_image_get_size_x(tmpImg),
01466                             cpl_image_get_size_y(tmpImg), CPL_TYPE_FLOAT);
01467                     kmo_image_fill(exp_mask, 1.);
01468 
01469                     combined_noise = NULL ;
01470                     if (cube_counter_noise > 0 && cube_noise[0] != NULL) {
01471                         combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
01472                     }
01473                 } else {
01474                     cpl_msg_error(__func__, "No cube found with this obj name");
01475                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01476                     return -1 ;
01477                 } 
01478                 for (jj = 0; jj < nr_data; jj++) {
01479                     cpl_imagelist_delete(cube_data[jj]); 
01480                     if (cube_counter_noise > 0) 
01481                         cpl_imagelist_delete(cube_noise[jj]); 
01482                 }
01483                 cpl_free(cube_data); 
01484                 cpl_free(cube_noise);
01485  
01486                 fn_out = COMBINED_CUBE;
01487                 if (!suppress_extension) {
01488                     char tmp_suffix[1024];
01489                     tmp_suffix[0] = '\0';
01490 
01491                     if (arm_name_struct->telluricCnt[i] == 
01492                             arm_name_struct->namesCnt[i]) {
01493                         strcat(tmp_suffix, "_telluric");
01494                     }
01495                     if (nb_illum_corr > 0)  strcat(tmp_suffix, "_illum");
01496                     if (sky_tweak)          strcat(tmp_suffix, "_skytweak");
01497 
01498                     if (strlen(tmp_suffix) > 0) {
01499                         fn_suffix = cpl_sprintf("_%s_%s", 
01500                                 arm_name_struct->names[i], tmp_suffix);
01501                     } else {
01502                         fn_suffix = cpl_sprintf("_%s", 
01503                                 arm_name_struct->names[i]);
01504                     }
01505                 } else {
01506                     fn_suffix = cpl_sprintf("_%d", suppress_index++);
01507                 }
01508 
01509                 // save combined cube
01510                 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01511                 kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, 
01512                         tmp_frame, NULL, parlist, cpl_func);
01513                 kmo_dfs_save_main_header(frameset, EXP_MASK, fn_suffix, 
01514                         tmp_frame, NULL, parlist, cpl_func);
01515                 kmo_dfs_save_cube(combined_data, fn_out, fn_suffix, 
01516                         header_data[0], 0./0.);
01517                 kmo_dfs_save_image(exp_mask, EXP_MASK, fn_suffix, 
01518                         header_data[0], 0./0.);
01519                 cpl_image_delete(exp_mask);
01520                     
01521                 if (header_noise[0] == NULL) {
01522                     header_noise[0]=cpl_propertylist_duplicate(header_data[0]);
01523                     tmp_str=cpl_propertylist_get_string(header_data[0],EXTNAME);
01524                     kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
01525                     extname = kmo_extname_creator(ifu_frame, tmp_int,EXT_NOISE);
01526                     kmclipm_update_property_string(header_noise[0], EXTNAME, 
01527                             extname, "FITS extension name");
01528                     cpl_free(extname);
01529                 }
01530                 kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix, 
01531                         header_noise[0], 0./0.);
01532 
01533                 cpl_free(fn_suffix);
01534                 for (jj = 0; jj < nr_data; jj++) {
01535                     cpl_propertylist_delete(header_data[jj]); 
01536                     cpl_propertylist_delete(header_noise[jj]); 
01537                 }
01538                 cpl_free(header_data);
01539                 cpl_free(header_noise);
01540                 cpl_imagelist_delete(combined_data);
01541                 if (combined_noise != NULL)
01542                     cpl_imagelist_delete(combined_noise);
01543             } 
01544         } else {
01545             /* Mapping_mode */
01546             nr_data = KMOS_NR_IFUS * 
01547                 cpl_frameset_count_tags(frameset,RECONSTRUCTED_CUBE);
01548             cube_data = (cpl_imagelist**)cpl_calloc(nr_data, 
01549                     sizeof(cpl_imagelist*));
01550             cube_noise = (cpl_imagelist**)cpl_calloc(nr_data, 
01551                     sizeof(cpl_imagelist*));
01552             header_data=(cpl_propertylist**)cpl_calloc(nr_data, 
01553                     sizeof(cpl_propertylist*));
01554             header_noise=(cpl_propertylist**)cpl_calloc(nr_data, 
01555                     sizeof(cpl_propertylist*));
01556 
01557             /* Initialise */
01558             for (jj = 0; jj < nr_data; jj++) {
01559                 cube_data[jj] = NULL ; 
01560                 cube_noise[jj] = NULL ; 
01561                 header_data[jj] = NULL ; 
01562                 header_noise[jj] = NULL ; 
01563             }
01564 
01565             cube_counter_data = 0;
01566             cube_counter_noise = 0;
01567             tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01568             while (tmp_frame != NULL ) {
01569                 fn_reconstr = cpl_frame_get_filename(tmp_frame);
01570 
01571                 kmo_init_fits_desc(&desc1);
01572                 desc1 = kmo_identify_fits_header(fn_reconstr);
01573                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01574                     idx = kmo_identify_index(fn_reconstr, ifu_nr, FALSE);
01575 
01576                     if (desc1.sub_desc[idx-1].valid_data) {
01577                         cpl_msg_debug(__func__, 
01578                                 "Load in cube_data - Frame: %s IFU: %d",
01579                                 fn_reconstr, ifu_nr) ;
01580                         cube_data[cube_counter_data] = kmclipm_imagelist_load(
01581                                 fn_reconstr, CPL_TYPE_FLOAT, idx);
01582                         if (edge_nan) 
01583                             kmo_edge_nan(cube_data[cube_counter_data], ifu_nr);
01584 
01585                         if (fast_mode) {
01586                             tmpImg = cpl_imagelist_collapse_median_create(
01587                                     cube_data[cube_counter_data]);
01588                             tmp_cube1 = cpl_imagelist_new();
01589                             cpl_imagelist_set(tmp_cube1, tmpImg, 0);
01590                             cpl_imagelist_delete(cube_data[cube_counter_data]);
01591                             cube_data[cube_counter_data] = tmp_cube1;
01592                         }
01593 
01594                         cpl_msg_debug(__func__, 
01595                                 "Load in header_data - Frame: %s IFU: %d",
01596                                 fn_reconstr, ifu_nr) ;
01597                         header_data[cube_counter_data] = 
01598                             kmclipm_propertylist_load(fn_reconstr, idx);
01599                         cpl_propertylist_update_string(
01600                                 header_data[cube_counter_data], 
01601                                 "ESO PRO FRNAME", fn_reconstr);
01602                         cpl_propertylist_update_int(
01603                                 header_data[cube_counter_data], 
01604                                 "ESO PRO IFUNR", ifu_nr);
01605                         cube_counter_data++;
01606                         cpl_msg_debug(__func__, "cube_counter_data: %d\n", 
01607                             cube_counter_data) ;
01608                     }
01609 
01610                     /* Load noise & subheader (if existing) */
01611                     if (desc1.ex_noise) {
01612                         idx = kmo_identify_index(fn_reconstr,ifu_nr,TRUE);
01613                         if (desc1.sub_desc[idx-1].valid_data) {
01614                             cpl_msg_debug(__func__, 
01615                                     "Load in cube_noise - Frame: %s IFU: %d",
01616                                     fn_reconstr, ifu_nr) ;
01617                             cube_noise[cube_counter_noise] =
01618                                 kmclipm_imagelist_load(fn_reconstr, 
01619                                         CPL_TYPE_FLOAT, idx);
01620 
01621                             if (edge_nan) 
01622                                 kmo_edge_nan(cube_noise[cube_counter_noise],
01623                                         ifu_nr);
01624                             if (fast_mode) {
01625                                 tmpImg=cpl_imagelist_collapse_median_create(
01626                                         cube_noise[cube_counter_noise]);
01627                                 tmp_cube1 = cpl_imagelist_new();
01628                                 cpl_imagelist_set(tmp_cube1, tmpImg, 0);
01629                                 cpl_imagelist_delete(
01630                                         cube_noise[cube_counter_noise]);
01631                                 cube_noise[cube_counter_noise] = tmp_cube1;
01632                             }
01633                             cpl_msg_debug(__func__, 
01634                                     "Load in header_noise - Frame: %s IFU: %d",
01635                                     fn_reconstr, ifu_nr) ;
01636                             header_noise[cube_counter_noise] = 
01637                                 kmclipm_propertylist_load(fn_reconstr, idx);
01638                             cube_counter_noise++;
01639                             cpl_msg_debug(__func__, "cube_counter_noise: %d\n", 
01640                                 cube_counter_noise) ;
01641                         }
01642                     }
01643                     cpl_error_reset();
01644                 } 
01645                 kmo_free_fits_desc(&desc1);
01646                 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01647             }
01648    
01649             if (cube_counter_noise == 0) {
01650                 cpl_free(cube_noise);
01651                 cube_noise = NULL ; 
01652             }
01653 
01654             if (cube_counter_data > 1) {
01655                 if (cube_counter_data == cube_counter_noise ||
01656                         cube_counter_noise == 0) {
01657                     kmo_priv_combine(cube_data, cube_noise, header_data,
01658                             header_noise, cube_counter_data, cube_counter_noise,
01659                             mapping_mode, "", comb_method, smethod, fmethod,
01660                             filename, cmethod, cpos_rej, cneg_rej, citer, cmin,
01661                             cmax, extrapol_enum, flux, &combined_data, 
01662                             &combined_noise, NULL);
01663                 } else {
01664                     cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
01665                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01666                     return -1 ;
01667                 }
01668             } else {
01669                 cpl_msg_warning(__func__, 
01670                         "There is only one reconstructed cube - Save it");
01671                 combined_data = cpl_imagelist_duplicate(cube_data[0]);
01672 
01673                 if (cube_noise[0] != NULL) {
01674                     combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
01675                 }
01676             }
01677             fn_out = COMBINED_CUBE;
01678             fn_suffix = cpl_sprintf("_%s", mapping_mode);
01679 
01680             // save combined cube
01681             tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01682             kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, tmp_frame, 
01683                     NULL, parlist, cpl_func);
01684             kmo_dfs_save_cube(combined_data, fn_out, fn_suffix, header_data[0],
01685                     0./0.);
01686 
01687             if (cube_counter_noise == 0) {
01688                 header_noise[0] = cpl_propertylist_duplicate(header_data[0]);
01689                 tmp_str = cpl_propertylist_get_string(header_data[0], EXTNAME);
01690                 kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
01691                 extname = kmo_extname_creator(ifu_frame, tmp_int, EXT_NOISE);
01692                 kmclipm_update_property_string(header_noise[0], EXTNAME,
01693                         extname, "FITS extension name");
01694                 cpl_free(extname);
01695             }
01696             kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix, 
01697                     header_noise[0], 0./0.);
01698             
01699             if (cube_counter_noise == 0) 
01700                 cpl_propertylist_delete(header_noise[0]); 
01701             cpl_free(fn_suffix);
01702             for (i = 0; i < cube_counter_data ; i++) {
01703                 cpl_propertylist_delete(header_data[i]); 
01704                 cpl_imagelist_delete(cube_data[i]);
01705             }
01706             for (i = 0; i < cube_counter_noise ; i++) {
01707                 cpl_propertylist_delete(header_noise[i]); 
01708                 cpl_imagelist_delete(cube_noise[i]); 
01709             }
01710             cpl_free(cube_data); 
01711             cpl_free(cube_noise);
01712             cpl_free(header_data);
01713             cpl_free(header_noise);
01714             cpl_imagelist_delete(combined_data); 
01715             cpl_imagelist_delete(combined_noise);
01716         }
01717     } 
01718     kmo_delete_armNameStruct(arm_name_struct);
01719 
01720     /* Collapse the reconstructed cubes if requested */
01721     if (collapse_reconstructed) {
01722         kmos_sci_red_collapse_cubes(RECONSTRUCTED_CUBE, frameset, parlist, 0.1,
01723                 "", DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
01724                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
01725     }
01726  
01727     /* Collapse the combined cubes if requested */
01728     if (collapse_combined) {
01729         kmos_sci_red_collapse_cubes(COMBINED_CUBE, frameset, parlist, 0.1, "",
01730                 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
01731                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
01732     }
01733     return 0;
01734 }
01735 
01738 /*----------------------------------------------------------------------------*/
01744 /*----------------------------------------------------------------------------*/
01745 static int kmos_sci_red_collapse_cubes(
01746         char                    *   pro_catg,
01747         cpl_frameset            *   frameset, 
01748         cpl_parameterlist       *   parlist,
01749         double                      threshold,
01750         const char              *   range,
01751         const char              *   cmethod,
01752         double                      cpos_rej,
01753         double                      cneg_rej,
01754         int                         citer,
01755         int                         cmin,
01756         int                         cmax)
01757 {
01758     cpl_frame           *   in_cube_frame ;
01759     cpl_frame           *   ref_spectrum_frame ;
01760     const char          *   fn_cube ;
01761     const char          *   pro_catg_out ;
01762     cpl_vector          *   ranges ;
01763     cpl_vector          *   spec_data_in ;
01764     cpl_vector          *   spec_lambda_in ;
01765     cpl_vector          *   identified_slices ;
01766     cpl_propertylist    *   sub_header_data ;
01767     cpl_propertylist    *   sub_header_noise ;
01768     cpl_propertylist    *   plist ;
01769     cpl_propertylist    *   pro_plist ;
01770     cpl_imagelist       *   data_in ;
01771     cpl_imagelist       *   noise_in ;
01772     cpl_image           *   data_out ;
01773     cpl_image           *   noise_out ;
01774     kmclipm_vector      *   kmclipm_tmp_vec ;
01775     double                  spec_crpix, spec_crval, spec_cdelt,
01776                             ifu_crpix, ifu_crval, ifu_cdelt ;
01777     char                *   filename ;
01778     int                     nr_devices, devnr, index_data, index_noise ;
01779     main_fits_desc          desc1 ;
01780     int                     i; 
01781 
01782     /* Check Inputs */
01783     if (frameset == NULL || parlist == NULL || pro_catg == NULL) return -1 ;
01784            
01785     if (!strcmp(pro_catg, COMBINED_CUBE)) {
01786         pro_catg_out = COMBINED_COLLAPSED ;
01787     } else if (!strcmp(pro_catg, RECONSTRUCTED_CUBE)) {
01788         pro_catg_out = RECONSTRUCTED_COLLAPSED ;
01789     } else {
01790         return -1 ;
01791     }
01792 
01793     /* Get ranges */
01794     ranges = kmo_identify_ranges(range);
01795 
01796     /* Get OH_SPEC */
01797     if (ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC)) {
01798         plist = kmos_dfs_load_sub_header(ref_spectrum_frame, 1, FALSE);
01799         spec_crpix = cpl_propertylist_get_double(plist, CRPIX1);
01800         spec_crval = cpl_propertylist_get_double(plist, CRVAL1);
01801         spec_cdelt = cpl_propertylist_get_double(plist, CDELT1);
01802         cpl_propertylist_delete(plist) ;
01803 
01804         /* Load OH lines data */
01805         kmclipm_tmp_vec = kmos_dfs_load_vector(ref_spectrum_frame, 1, FALSE) ;
01806         spec_data_in = kmclipm_vector_create_non_rejected(kmclipm_tmp_vec);
01807         kmclipm_vector_delete(kmclipm_tmp_vec);
01808 
01809         /* Convert threshold from percentage to absolute value */
01810         threshold = threshold * cpl_vector_get_max(spec_data_in);
01811 
01812         /* Create lambda-vector for OH-lines */
01813         spec_lambda_in = kmo_create_lambda_vec(
01814                 cpl_vector_get_size(spec_data_in), (int)spec_crpix, spec_crval,
01815                 spec_cdelt) ;
01816     } else {
01817         spec_data_in = NULL ;
01818         spec_lambda_in = NULL ;
01819     }
01820 
01821     /* Loop on the cubes with the requested PRO.CATG */
01822     in_cube_frame = kmo_dfs_get_frame(frameset, pro_catg);
01823     while (in_cube_frame != NULL ) {
01824         fn_cube = cpl_frame_get_filename(in_cube_frame);
01825         kmo_init_fits_desc(&desc1);
01826         desc1 = kmo_identify_fits_header(fn_cube);
01827 
01828         /* Create the Header and save the initial file */
01829         pro_plist = cpl_propertylist_new() ;
01830         cpl_propertylist_update_string(pro_plist,CPL_DFS_PRO_CATG,pro_catg_out);
01831         filename = cpl_sprintf("make_image_%s", fn_cube) ; 
01832         cpl_dfs_save_propertylist(frameset, NULL, parlist, frameset,
01833                 in_cube_frame, "kmos_sci_red", pro_plist, NULL, VERSION,
01834                 filename) ;
01835         cpl_propertylist_delete(pro_plist) ;
01836 
01837         if (desc1.ex_noise == TRUE)     nr_devices = desc1.nr_ext / 2;
01838         else                            nr_devices = desc1.nr_ext;
01839         for (i = 1; i <= nr_devices; i++) {
01840             if (desc1.ex_noise == FALSE) devnr=desc1.sub_desc[i-1].device_nr;
01841             else                         devnr=desc1.sub_desc[2*i-1].device_nr;
01842             if (desc1.ex_badpix == FALSE) 
01843                 index_data = kmo_identify_index_desc(desc1, devnr, FALSE);
01844             else 
01845                 index_data = kmo_identify_index_desc(desc1, devnr, 2);
01846             index_noise = 0 ;
01847             if (desc1.ex_noise) 
01848                 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE);
01849 
01850             /* Load the Extension Header */
01851             sub_header_data = kmos_dfs_load_sub_header(in_cube_frame, devnr, 
01852                     FALSE);
01853 
01854             /* Load noise */
01855             sub_header_noise = NULL ;
01856             if (desc1.ex_noise) 
01857                sub_header_noise=kmos_dfs_load_sub_header(in_cube_frame, devnr, 
01858                        TRUE);
01859 
01860             /* If Data Valid */
01861             if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
01862                 /* Interpolate oh-lines to fit input data */
01863                 ifu_crpix = cpl_propertylist_get_double(sub_header_data,CRPIX3);
01864                 ifu_crval = cpl_propertylist_get_double(sub_header_data,CRVAL3);
01865                 ifu_cdelt = cpl_propertylist_get_double(sub_header_data,CDELT3);
01866 
01867                 if (spec_data_in == NULL) {
01868                     identified_slices = kmo_identify_slices(ranges, ifu_crpix,
01869                             ifu_crval, ifu_cdelt, desc1.naxis3);
01870                 } else {
01871                     identified_slices = kmo_identify_slices_with_oh(
01872                             spec_data_in, spec_lambda_in, ranges, threshold,
01873                             ifu_crpix, ifu_crval, ifu_cdelt, desc1.naxis3);
01874                 }
01875                 kmos_sci_red_clean_plist(sub_header_data) ;
01876     
01877                 /* Load data */
01878                 data_in = kmos_dfs_load_cube(in_cube_frame, devnr, FALSE) ;
01879 
01880                 /* Load noise, if existing */
01881                 noise_in = NULL ;
01882                 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data)
01883                     noise_in = kmos_dfs_load_cube(in_cube_frame, devnr, TRUE) ;
01884 
01885                 /* Process */
01886                 noise_out = NULL ;
01887                 kmclipm_make_image(data_in, noise_in, &data_out, &noise_out, 
01888                         identified_slices, cmethod, cpos_rej, cneg_rej, citer, 
01889                         cmax, cmin);
01890                 cpl_imagelist_delete(data_in); 
01891                 if (noise_in != NULL) 
01892                     cpl_imagelist_delete(noise_in);
01893                 cpl_vector_delete(identified_slices);
01894                 
01895                 /* Save Data */
01896                 kmclipm_image_save(data_out, filename, CPL_BPP_IEEE_FLOAT, 
01897                         sub_header_data, CPL_IO_EXTEND, 0./0.) ;
01898 
01899                 /* Process & save noise, if existing */
01900                 if (desc1.ex_noise) {
01901                     kmclipm_image_save(noise_out, filename, CPL_BPP_IEEE_FLOAT, 
01902                             sub_header_noise, CPL_IO_EXTEND, 0./0.);
01903                 }
01904 
01905                 /* Free memory */
01906                 cpl_image_delete(data_out); 
01907                 if (noise_out != NULL) cpl_image_delete(noise_out);
01908             } else {
01909                 kmos_sci_red_clean_plist(sub_header_data) ;
01910 
01911                 /* invalid IFU, just save sub_headers */
01912                 cpl_propertylist_save(sub_header_data, filename, CPL_IO_EXTEND);
01913         
01914                  if (desc1.ex_noise) 
01915                     cpl_propertylist_save(sub_header_noise, filename, 
01916                             CPL_IO_EXTEND);
01917             }
01918             cpl_propertylist_delete(sub_header_data);
01919             if (sub_header_noise != NULL) 
01920                 cpl_propertylist_delete(sub_header_noise);
01921         }
01922         cpl_free(filename) ;
01923         kmo_free_fits_desc(&desc1);
01924 
01925         /* Next candidate */
01926         in_cube_frame = kmo_dfs_get_frame(frameset, NULL);
01927     }
01928 
01929     if (spec_data_in != NULL) cpl_vector_delete(spec_data_in); 
01930     if (spec_lambda_in != NULL) cpl_vector_delete(spec_lambda_in); 
01931     return 0 ;
01932 
01933 }
01934 
01935 /*----------------------------------------------------------------------------*/
01941 /*----------------------------------------------------------------------------*/
01942 static int kmos_sci_red_clean_plist(cpl_propertylist * plist) 
01943 {
01944     if (cpl_propertylist_has(plist, CRPIX3))
01945         cpl_propertylist_erase(plist, CRPIX3);
01946     if (cpl_propertylist_has(plist, CRVAL3))
01947         cpl_propertylist_erase(plist, CRVAL3);
01948     if (cpl_propertylist_has(plist, CDELT3))
01949         cpl_propertylist_erase(plist, CDELT3);
01950     if (cpl_propertylist_has(plist, CTYPE3))
01951         cpl_propertylist_erase(plist, CTYPE3);
01952     if (cpl_propertylist_has(plist, CUNIT3))
01953         cpl_propertylist_erase(plist, CUNIT3);
01954     if (cpl_propertylist_has(plist, CD1_3))
01955         cpl_propertylist_erase(plist, CD1_3);
01956     if (cpl_propertylist_has(plist, CD2_3))
01957         cpl_propertylist_erase(plist, CD2_3);
01958     if (cpl_propertylist_has(plist, CD3_3))
01959         cpl_propertylist_erase(plist, CD3_3);
01960     if (cpl_propertylist_has(plist, CD3_2))
01961         cpl_propertylist_erase(plist, CD3_2);
01962     if (cpl_propertylist_has(plist, CD3_1))
01963         cpl_propertylist_erase(plist, CD3_1);
01964 
01965     return 0 ;
01966 }
01967 
01968 /*----------------------------------------------------------------------------*/
01975 /*----------------------------------------------------------------------------*/
01976 static int kmos_sci_red_check_inputs(
01977         cpl_frameset            *   frameset, 
01978         int                     *   mapping_id)
01979 {
01980     int     nb_science, nb_xcal, nb_ycal, nb_lcal, nb_wave_band,
01981             nb_master_flat, nb_illum_corr, nb_telluric, nb_oh_spec ;
01982     cpl_error_code          err ;
01983     const cpl_frame     *   frame1 ;
01984     const cpl_frame     *   frame2 ;
01985     int                     next1, next2, mapping_id_loc, mapping_id_curr ;
01986     cpl_propertylist    *   mh ;
01987     const char          *   tmp_str ;
01988 
01989     /* Check Entries */
01990     if (frameset == NULL || mapping_id == NULL) return -1;
01991 
01992     /* Count frames */
01993     nb_science = cpl_frameset_count_tags(frameset, SCIENCE) ;
01994     nb_xcal = cpl_frameset_count_tags(frameset, XCAL) ;
01995     nb_ycal = cpl_frameset_count_tags(frameset, YCAL) ;
01996     nb_lcal = cpl_frameset_count_tags(frameset, LCAL) ;
01997     nb_wave_band = cpl_frameset_count_tags(frameset, WAVE_BAND) ;
01998     nb_master_flat = cpl_frameset_count_tags(frameset, MASTER_FLAT);
01999     nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
02000     nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
02001     nb_oh_spec = cpl_frameset_count_tags(frameset, OH_SPEC) ;
02002 
02003     /* Checks  */
02004     if (nb_science < 1) {
02005         cpl_msg_error(__func__, "At least one SCIENCE frame is required") ;
02006         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02007         return 0 ;
02008     }
02009     if (nb_science == 1) {
02010         cpl_msg_warning(__func__, 
02011                 "Only 1 SCIENCE: no sky subtraction - reconstruct all IFUs");
02012     }
02013     if (nb_xcal != 1 || nb_ycal != 1 || nb_lcal != 1) {
02014         cpl_msg_error(__func__, "Exactly 1 XCAL/YCAL/LCAL expected") ;
02015         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02016         return 0 ;
02017     }
02018     if (nb_wave_band != 1) {
02019         cpl_msg_error(__func__, "At most one WAVE_BAND frame expected") ;
02020         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02021         return 0 ;
02022     }
02023     
02024     if (nb_master_flat > 1 || nb_illum_corr > 1 || nb_telluric > 1 ||
02025             nb_oh_spec > 1) {
02026         cpl_msg_error(__func__, 
02027             "MASTER_FLAT/ILLUM_CORR/OH_SPEC/TELLURIC: 0 or 1 frame expected") ;
02028         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02029         return 0 ;
02030     }
02031 
02032     /* filter_id, grating_id and rotator offset match all detectors */
02033     err = CPL_ERROR_NONE ;
02034     err += kmo_check_frameset_setup(frameset, SCIENCE, TRUE, FALSE, TRUE);
02035     err += kmo_check_frame_setup(frameset, SCIENCE, YCAL, TRUE, FALSE, TRUE);
02036     err += kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
02037     err += kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
02038     if (nb_master_flat > 0) err += kmo_check_frame_setup(frameset, XCAL,
02039             MASTER_FLAT, TRUE, FALSE, TRUE);
02040     if (nb_telluric > 0)    err += kmo_check_frame_setup(frameset, XCAL, 
02041             TELLURIC, TRUE, FALSE, TRUE);
02042     if (nb_oh_spec > 0)     err += kmo_check_oh_spec_setup(frameset, XCAL);
02043 
02044     /* Check XCAL */
02045     frame1 = kmo_dfs_get_frame(frameset, XCAL);
02046     next1 = cpl_frame_get_nextensions(frame1);
02047     if (next1 % KMOS_NR_DETECTORS) {
02048         cpl_msg_error(__func__, "XCAL wrong format") ;
02049         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02050         return 0 ;
02051     }
02052     /* Check YCAL */
02053     frame2 = kmo_dfs_get_frame(frameset, YCAL);
02054     next2 = cpl_frame_get_nextensions(frame2);
02055     if (next1 != next2) {
02056         cpl_msg_error(__func__, "YCAL wrong format") ;
02057         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02058         return 0 ;
02059     }
02060     /* Check LCAL */
02061     frame2 = kmo_dfs_get_frame(frameset, LCAL);
02062     next2 = cpl_frame_get_nextensions(frame2);
02063     if (next1 != next2) {
02064         cpl_msg_error(__func__, "LCAL wrong format") ;
02065         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02066         return 0 ;
02067     }
02068     /* Check MASTER_FLAT */
02069     if (nb_master_flat > 1) {
02070         frame2 = kmo_dfs_get_frame(frameset, MASTER_FLAT);
02071         next2 = cpl_frame_get_nextensions(frame2);
02072         if (next2 % (2*KMOS_NR_DETECTORS)) {
02073             cpl_msg_error(__func__, "MASTER_FLAT wrong format") ;
02074             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02075             return 0 ;
02076         }
02077     }
02078     /* Check ILLUM_CORR */
02079     if (nb_illum_corr > 1) {
02080         frame2 = kmo_dfs_get_frame(frameset, ILLUM_CORR);
02081         next2 = cpl_frame_get_nextensions(frame2);
02082         if (next2 != 24 && next2 != 48) {
02083             cpl_msg_error(__func__, "MASTER_FLAT wrong format") ;
02084             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02085             return 0 ;
02086         }
02087     }
02088     /* Check TELLURIC */
02089     if (nb_illum_corr > 1) {
02090         frame2 = kmo_dfs_get_frame(frameset, TELLURIC);
02091         next2 = cpl_frame_get_nextensions(frame2);
02092         if (next2 != 24 && next2 != 48) {
02093             cpl_msg_error(__func__, "TELLURIC wrong format") ;
02094             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02095             return 0 ;
02096         }
02097     }
02098     
02099     /* Loop on the SCIENCE frames */
02100     frame2 = kmo_dfs_get_frame(frameset, SCIENCE);
02101     mapping_id_loc = -1 ;
02102     while (frame2 != NULL ) {
02103         next2 = cpl_frame_get_nextensions(frame2);
02104         if (next2 != 3) {
02105             cpl_msg_error(__func__, "SCIENCE wrong format") ;
02106             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02107             return 0 ;
02108         }
02109         
02110         mh = cpl_propertylist_load(cpl_frame_get_filename(frame2), 0);
02111         tmp_str = cpl_propertylist_get_string(mh, TPL_ID);
02112         if (!strcmp(tmp_str, MAPPING8))             mapping_id_curr = 1 ;
02113         else if (strcmp(tmp_str, MAPPING24) == 0)   mapping_id_curr = 2 ;
02114         else                                        mapping_id_curr = 0 ;
02115         cpl_propertylist_delete(mh);
02116         
02117         if (mapping_id_loc < 0)    mapping_id_loc = mapping_id_curr ;
02118         if (mapping_id_curr != mapping_id_loc) {
02119             cpl_msg_error(__func__, "Inconsistent MAPPING information") ;
02120             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
02121             return 0 ;
02122         }
02123         frame2 = kmo_dfs_get_frame(frameset, NULL);
02124     }
02125 
02126     /* Verify that XCAL / YCAL were generated together */
02127     err += kmo_check_frame_setup_md5_xycal(frameset);
02128     /* Verify that XCAL and YCAL / LCAL were generated together */
02129     err += kmo_check_frame_setup_md5(frameset);
02130     /* b_start/b_end/b_samples used for LCAL and TELLURIC were the same */
02131     err += kmo_check_frame_setup_sampling(frameset);
02132 
02133     if (err != CPL_ERROR_NONE) {
02134         cpl_msg_warning(__func__, "Frames are inconsistent") ;
02135         return 0 ;
02136     }
02137 
02138     /* Return */
02139     *mapping_id = mapping_id_loc ;
02140     return 1 ;
02141 }
02142 
02143 /*----------------------------------------------------------------------------*/
02150 /*----------------------------------------------------------------------------*/
02151 static double kmos_sci_red_get_zpoint(
02152         cpl_frame   *   frame, 
02153         int             ifu_nr)
02154 {
02155     cpl_propertylist    *   plist ;
02156     double                  zpoint ;
02157     int                     nb_ext, ext_nb ;
02158 
02159     /* Check entries */
02160     if (frame == NULL) return -1.0 ;
02161     if (cpl_error_get_code() != CPL_ERROR_NONE) return -1.0 ;
02162 
02163     /* Get the number of extentions */
02164     nb_ext = cpl_frame_get_nextensions(frame);
02165     
02166     /* Compute ext_nb */
02167     if (nb_ext == KMOS_NR_IFUS)             ext_nb = ifu_nr ;
02168     else if (nb_ext == 2 * KMOS_NR_IFUS)    ext_nb = 2 * ifu_nr - 1 ;
02169     else return -1.0 ;
02170     
02171     /* Get QC ZPOINT */
02172     plist = cpl_propertylist_load(cpl_frame_get_filename(frame), ext_nb);
02173     zpoint = cpl_propertylist_get_double(plist, "ESO QC ZPOINT") ;
02174     cpl_propertylist_delete(plist) ;
02175 
02176     if (cpl_error_get_code() != CPL_ERROR_NONE) {
02177         cpl_error_reset() ;
02178         zpoint = -1.0 ;
02179     }
02180 
02181     return zpoint ;
02182 }
02183  
02184 /*----------------------------------------------------------------------------*/
02190 /*----------------------------------------------------------------------------*/
02191 static double kmos_sci_red_get_f0(
02192         const char      *   filter_id,
02193         int                 lam_dim,
02194         double              lam_start,
02195         double              lam_delta)
02196 {
02197     double  f_0 = -1.0 ;
02198     double cent_wl = lam_start + (lam_delta * (lam_dim/2.0)) ;
02199     if (!strcmp(filter_id, "H"))                    f_0 = 1.133e-9 ;
02200     if (!strcmp(filter_id, "HK") && cent_wl < 1.9)  f_0 = 1.133e-9 ;
02201     if (!strcmp(filter_id, "HK") && cent_wl >= 1.9) f_0 = 4.283e-10 ;
02202     if (!strcmp(filter_id, "K"))                    f_0 = 4.283e-10 ;
02203     if (!strcmp(filter_id, "YJ"))                   f_0 = 3.129e-9 ;
02204     if (!strcmp(filter_id, "IZ"))                   f_0 = 7.63e-9 ;
02205     return f_0 ;
02206 }
02207  
02208