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