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