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