KMOS Pipeline Reference Manual  1.3.16
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     int                 *   qc_output_unit ;
00547     int                 *   bounds ;
00548     gridDefinition          gd ;
00549     armNameStruct       *   arm_name_struct ;
00550        
00551     cpl_propertylist    *   plist ;
00552     cpl_polynomial      *   oh_lcorr_coeffs ;
00553     cpl_vector          *   ifus ;
00554     cpl_array           **  unused_ifus_before ;
00555     cpl_array           **  unused_ifus_after ;
00556     cpl_frame           *   sky_frame ;
00557     cpl_frame           *   sky_as_object_frame ;
00558     cpl_frame           *   ref_spectrum_frame ;
00559     cpl_frame           *   xcal_frame ;
00560     cpl_frame           *   ycal_frame ;
00561     cpl_frame           *   lcal_frame ;
00562     cpl_frame           *   flat_frame ;
00563     cpl_frame           *   telluric_frame ;
00564     cpl_frame           *   tmp_frame ;
00565         
00566     cpl_table           *   band_table ;
00567 
00568     cpl_imagelist       *   combined_data ;
00569     cpl_imagelist       *   combined_noise ;
00570     cpl_imagelist       *   tmp_cube1 ;
00571     cpl_imagelist       *   tmp_cube2 ;
00572     
00573     cpl_image           *   tmpImg ;
00574     cpl_image           *   exp_mask ;
00575     cpl_image           *   illum_data ;
00576     cpl_image           *   illum_noise ;
00577     
00578     cpl_imagelist       **  cube_data ;
00579     cpl_imagelist       **  cube_noise ;
00580     cpl_imagelist       **  cube_interim_object ;
00581     cpl_imagelist       **  cube_interim_sky  ;
00582 
00583     cpl_propertylist    **  header_data ;
00584     cpl_propertylist    **  header_noise ;
00585     cpl_propertylist    **  header_sky ;
00586 
00587     kmclipm_vector      *   telluric_data ;
00588     kmclipm_vector      *   telluric_noise ;
00589 
00590     /* Initialise */
00591     print_once = FALSE ;
00592     cube_counter_data = cube_counter_noise = 0 ; 
00593     do_sky_subtraction = FALSE ;
00594     suppress_index = 0 ;
00595     mapping_id = -1 ;
00596     combined_data = combined_noise = NULL ;
00597     sky_as_object_frame = NULL ;
00598 
00599     /* Check entries */
00600     if (parlist == NULL || frameset == NULL) {
00601         cpl_msg_error(__func__, "Null Inputs") ;
00602         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00603         return -1 ;
00604     }
00605 
00606     /* Get parameters */
00607     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.flux");
00608     flux = cpl_parameter_get_bool(par);
00609     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.background");
00610     background = cpl_parameter_get_bool(par);
00611     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.imethod");
00612     imethod = cpl_parameter_get_string(par) ;
00613     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.smethod");
00614     smethod = cpl_parameter_get_string(par) ;
00615     par = cpl_parameterlist_find_const(parlist,
00616             "kmos.kmos_sci_red.neighborhoodRange");
00617     neighborhoodRange = cpl_parameter_get_double(par) ;
00618     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.method");
00619     comb_method = cpl_parameter_get_string(par) ;
00620     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.fmethod");
00621     fmethod = cpl_parameter_get_string(par) ;
00622     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.filename");
00623     filename = cpl_parameter_get_string(par) ;
00624     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.ifus");
00625     ifus_txt = cpl_parameter_get_string(par) ;
00626     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.name");
00627     name = cpl_parameter_get_string(par) ;
00628     kmos_band_pars_load(parlist, "kmos.kmos_sci_red");
00629     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.extrapolate");
00630     extrapolate = cpl_parameter_get_bool(par);
00631     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.fast_mode");
00632     fast_mode = cpl_parameter_get_bool(par);
00633     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.edge_nan");
00634     edge_nan = cpl_parameter_get_bool(par);
00635     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_combine");
00636     no_combine = cpl_parameter_get_bool(par);
00637     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.no_subtract");
00638     no_subtract = cpl_parameter_get_bool(par);
00639     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.sky_tweak");
00640     sky_tweak = cpl_parameter_get_bool(par);
00641     par = cpl_parameterlist_find_const(parlist,
00642             "kmos.kmos_sci_red.discard_subband");
00643     discard_subband = cpl_parameter_get_bool(par);
00644     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_sci_red.tbsub");
00645     tbsub = cpl_parameter_get_bool(par);
00646     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.oscan");
00647     oscan = cpl_parameter_get_bool(par);
00648     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_sci_red.pix_scale");
00649     pix_scale = cpl_parameter_get_double(par) ;
00650     par = cpl_parameterlist_find_const(parlist,
00651             "kmos.kmos_sci_red.xcal_interpolation");
00652     xcal_interpolation = cpl_parameter_get_bool(par);
00653     par = cpl_parameterlist_find_const(parlist,
00654             "kmos.kmos_sci_red.suppress_extension");
00655     suppress_extension = cpl_parameter_get_bool(par);
00656     par = cpl_parameterlist_find_const(parlist, 
00657             "kmos.kmos_sci_red.obj_sky_table");
00658     fn_obj_sky_table = cpl_parameter_get_string(par) ;
00659     kmos_combine_pars_load(parlist, "kmos.kmos_sci_red", &cmethod, &cpos_rej, 
00660             &cneg_rej, &citer, &cmin, &cmax, FALSE);
00661     par = cpl_parameterlist_find_const(parlist,
00662             "kmos.kmos_sci_red.velocity_offset");
00663     velo_offset = cpl_parameter_get_double(par) ;
00664     velo_corr = 1. + velo_offset * 1000. / CPL_PHYS_C;
00665     velo_corr_ptr = &velo_corr;
00666     par = cpl_parameterlist_find_const(parlist,
00667             "kmos.kmos_sci_red.save_interims");
00668     save_interims = cpl_parameter_get_bool(par);
00669     par = cpl_parameterlist_find_const(parlist,
00670             "kmos.kmos_sci_red.collapse_combined");
00671     collapse_combined = cpl_parameter_get_bool(par);
00672     par = cpl_parameterlist_find_const(parlist,
00673             "kmos.kmos_sci_red.collapse_reconstructed");
00674     collapse_reconstructed = cpl_parameter_get_bool(par);
00675 
00676     /* Check Parameters */
00677     if (strcmp(imethod, "NN") && strcmp(imethod, "lwNN") && 
00678             strcmp(imethod, "swNN") && strcmp(imethod, "MS") && 
00679             strcmp(imethod, "CS")) {
00680         cpl_msg_error(__func__, 
00681                 "imethod must be 'NN','lwNN','swNN','MS' or 'CS'") ;
00682         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00683         return -1 ;
00684     }
00685     if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
00686         cpl_msg_error(__func__, 
00687                 "smethod must be 'NN' or 'CS'") ;
00688         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00689         return -1 ;
00690     }
00691     if (neighborhoodRange <= 0.0) {
00692         cpl_msg_error(__func__, 
00693                 "neighborhoodRange must be greater than 0.0") ;
00694         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00695         return -1 ;
00696     }
00697     if (strcmp(comb_method, "none") && strcmp(comb_method, "header") &&
00698             strcmp(comb_method, "center") && strcmp(comb_method, "user")) {
00699         cpl_msg_error(__func__, 
00700             "shift methods must be 'none', 'header', 'center' or 'user'") ;
00701         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00702         return -1 ;
00703     }
00704     if (strcmp(ifus_txt, "") && strcmp(name, "")) {
00705         cpl_msg_error(__func__, 
00706                 "name and IFU indices cannot be both provided") ;
00707         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00708         return -1 ;
00709     }
00710     if (strcmp(smethod, "NN") && strcmp(smethod, "CS")) {
00711         cpl_msg_error(__func__, "smethod must be 'NN' or 'CS'") ;
00712         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00713         return -1 ;
00714     }
00715     if (!strcmp(smethod, "NN") && extrapolate == TRUE) {
00716         cpl_msg_error(__func__,
00717                 "extrapolation in not compatible with smethod 'NN'");
00718         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00719         return -1 ;
00720     }
00721     if (!strcmp(smethod, "CS")) smethod = "BCS";
00722     if (!strcmp(smethod, "BCS") && extrapolate == TRUE) 
00723         extrapol_enum = BCS_NATURAL;
00724     else
00725         extrapol_enum = NONE_NANS;
00726 
00727     if (no_subtract && sky_tweak) {
00728         cpl_msg_error(__func__,"no_subtract and sky_tweak cannot be both TRUE");
00729         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00730         return -1 ;
00731     }
00732     if (pix_scale < 0.01 || pix_scale > 0.4) {
00733         cpl_msg_error(__func__, "pix_scale must be between 0.01 and 0.4");
00734         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00735         return -1 ;
00736     }
00737  
00738     if (cpl_frameset_count_tags(frameset, SCIENCE) == 1 || no_subtract) {
00739         no_combine = TRUE;
00740         cpl_msg_info(__func__, 
00741                 "--no_combine set to TRUE (1 SCIENCE frame or --no_subtract");
00742     }
00743 
00744     /* Identify the RAW and CALIB frames in the input frameset */
00745     if (kmo_dfs_set_groups(frameset, "kmos_sci_red") != 1) {
00746         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00747         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00748         return -1 ;
00749     }
00750     
00751     /* Check the inputs consistency */
00752     if (kmos_sci_red_check_inputs(frameset, pix_scale, &mapping_id) != 1) {
00753         cpl_msg_error(__func__, "Input frameset is not consistent") ;
00754         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00755         return -1 ;
00756     }
00757     if (mapping_id == 0)    mapping_mode = NULL ;
00758     if (mapping_id == 1)    mapping_mode = "mapping8" ;
00759     if (mapping_id == 2)    mapping_mode = "mapping24" ;
00760 
00761     /* Instrument setup */
00762     suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset,SCIENCE),TRUE,FALSE);
00763     cpl_msg_info(__func__, "Detected instrument setup:   %s", suffix+1);
00764     cpl_free(suffix); 
00765  
00766     /* Load IFUS if specified */
00767     if (strcmp(ifus_txt, "")) {
00768         nb_science = cpl_frameset_count_tags(frameset, SCIENCE);
00769         ifus = kmo_identify_values(ifus_txt);
00770         if (ifus == NULL || cpl_vector_get_size(ifus) != nb_science) {
00771             if (ifus != NULL) cpl_vector_delete(ifus);
00772             cpl_msg_error(__func__, "ifus size must match the science frames") ;
00773             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00774             return -1 ;
00775         }
00776     } else {
00777         ifus = NULL ;
00778     }
00779 
00780     /* Mapping mode */
00781     if (mapping_id > 0) {
00782         if ((ifus != NULL) || (strcmp(name, ""))) {
00783             cpl_msg_warning(__func__,"Mapping Mode ٍ+ Specific IFUs requested") ;
00784         } else {
00785             if (!strcmp(smethod, "BCS")) {
00786                 extrapol_enum = BCS_NATURAL;
00787                 cpl_msg_info(__func__, "Mapping Mode : extrapolation set") ;
00788             }
00789         }
00790     }
00791 
00792     /* Check which IFUs are active for all frames */
00793     unused_ifus_before = kmo_get_unused_ifus(frameset, 1, 1);
00794     unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
00795     kmo_print_unused_ifus(unused_ifus_before, FALSE);
00796     kmo_free_unused_ifus(unused_ifus_before);
00797 
00798     /* Setup grid definition, wavelength start and end are set later */
00799     kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.);
00800 
00801     /* Get frames */
00802     xcal_frame = kmo_dfs_get_frame(frameset, XCAL) ;
00803     ycal_frame = kmo_dfs_get_frame(frameset, YCAL) ;
00804     lcal_frame = kmo_dfs_get_frame(frameset, LCAL) ;
00805     flat_frame = kmo_dfs_get_frame(frameset, MASTER_FLAT) ;
00806     ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC) ;
00807     nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
00808 
00809     /* Get left and right bounds of IFUs from XCAL */
00810     header_tmp = kmo_dfs_load_primary_header(frameset, XCAL);
00811     bounds = kmclipm_extract_bounds(header_tmp);
00812     cpl_propertylist_delete(header_tmp);
00813     if (bounds == NULL) {
00814         if (ifus != NULL) cpl_vector_delete(ifus);
00815         kmo_free_unused_ifus(unused_ifus_after);
00816         cpl_msg_error(__func__, "Cannot compute bounds") ;
00817         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00818         return -1 ;
00819     }
00820 
00821     /* armNameStruct: objects that need to be reconstructed and their 
00822        associated sky. Valid STD frames with objects and associated sky.
00823        Get valid object names, either one object name in several frames, 
00824        or all object names */
00825     if (!strcmp(fn_obj_sky_table, "")) {
00826         arm_name_struct = kmo_create_armNameStruct(frameset, SCIENCE, ifus,
00827                 name, unused_ifus_after, bounds, mapping_mode, no_subtract);
00828         /* TODO : need to save ?? */
00829         kmo_save_objSkyStruct(arm_name_struct->obj_sky_struct);
00830     } else {
00831         // read in obj/sky-table
00832         objSkyStruct *obj_sky_struct = NULL;
00833         obj_sky_struct = kmo_read_objSkyStruct(fn_obj_sky_table, frameset, 
00834                 SCIENCE);
00835 
00836         /* Check if any sky-IFUs have been specified not beeing the */
00837         /* same IFU# for objects. */
00838         // In this case sky_tweak must be activated
00839         for (i = 0; i < obj_sky_struct->size; i++) {
00840             if (obj_sky_struct->table[i].objFrame != NULL) {
00841                 for (j = 0; j < KMOS_NR_IFUS; j++) {
00842                     if ((obj_sky_struct->table[i].skyIfus[j] > 0) && 
00843                             (sky_tweak == FALSE)) {
00844                         kmo_print_objSkyStruct(obj_sky_struct);
00845                         kmo_delete_objSkyStruct(obj_sky_struct);
00846                         cpl_msg_error(__func__, 
00847             "--sky_tweak needs to be set when sky are used from other IFUs");
00848                         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00849                         return -1 ;
00850                     }
00851                 }
00852             }
00853         }
00854         arm_name_struct = kmo_create_armNameStruct2(obj_sky_struct, frameset, 
00855                 SCIENCE, ifus, name, unused_ifus_after, bounds, mapping_mode, 
00856                 no_subtract);
00857     }
00858     if (ifus != NULL) cpl_vector_delete(ifus);
00859     if (arm_name_struct == NULL) {
00860         kmo_free_unused_ifus(unused_ifus_after);
00861         cpl_free(bounds);
00862         cpl_msg_error(__func__, "Cannot compute ARM/name structure") ;
00863         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00864         return -1 ;
00865     }
00866     kmo_print_armNameStruct(frameset, arm_name_struct);
00867     
00868     /* Check Telluric availability for each Object */
00869     /* in mapping-mode check if for all IFUs there is either no  */
00870     /* telluric at all or the same number of tellurics than object names */
00871     nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
00872     if (nb_telluric > 0 && mapping_id > 0) {
00873         for (i = 0; i < arm_name_struct->nrNames; i++) {
00874             if (arm_name_struct->telluricCnt[i] != arm_name_struct->namesCnt[i]
00875                  && (arm_name_struct->telluricCnt[i] != 0)) {
00876                 cpl_msg_error(__func__, "Mosaics need a TELLURIC per detector");
00877                 cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE) ;
00878                 return -1 ;
00879             }
00880         }
00881     }
00882 
00883     /* Allocate data */
00884     cube_data=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, sizeof(cpl_imagelist*));
00885     cube_noise=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS,sizeof(cpl_imagelist*));
00886     header_data = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00887             sizeof(cpl_propertylist*));
00888     header_noise = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00889             sizeof(cpl_propertylist*));
00890     if (save_interims) {
00891         cube_interim_object=(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, 
00892                 sizeof(cpl_imagelist*));
00893         cube_interim_sky =(cpl_imagelist**)cpl_calloc(KMOS_NR_IFUS, 
00894                 sizeof(cpl_imagelist*));
00895         header_sky = (cpl_propertylist**)cpl_calloc(KMOS_NR_IFUS, 
00896                 sizeof(cpl_propertylist*));
00897     }
00898 
00899     /* Loop all science frames containing at least one object */
00900     cpl_msg_info(__func__, "Reconstructing & saving cubes with objects");
00901     for (sf = 0; sf < arm_name_struct->size; sf++) {
00902         fn_obj = cpl_frame_get_filename(
00903                 arm_name_struct->obj_sky_struct->table[sf].objFrame);
00904         if ((main_header = kmclipm_propertylist_load(fn_obj, 0)) == NULL) {
00905             kmo_free_unused_ifus(unused_ifus_after);
00906             cpl_free(bounds);
00907             kmo_delete_armNameStruct(arm_name_struct);
00908             cpl_free(qc_output_unit) ;
00909             cpl_free(cube_data) ;
00910             cpl_free(cube_noise) ;
00911             cpl_free(header_data) ;
00912             cpl_free(header_noise) ;
00913             if (save_interims) {
00914                 cpl_free(cube_interim_object) ;
00915                 cpl_free(cube_interim_sky) ;
00916                 cpl_free(header_sky) ;
00917             }
00918             cpl_msg_error(__func__, "Cannot Load main header");
00919             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00920             return -1 ;
00921         }
00922         actual_msg_level = cpl_msg_get_level();
00923 
00924         /* Hold the QC parameter */
00925         qc_output_unit = cpl_calloc(KMOS_NR_IFUS, sizeof(int)) ;
00926 
00927         /* Reconstruct science frame */
00928         cpl_msg_info(__func__, "   > processing frame: %s", fn_obj);
00929         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
00930 
00931             /* Initialise */
00932             cube_data[ifu_nr-1] = cube_noise[ifu_nr-1] = NULL ; 
00933 
00934             sky_ifu_nr = ifu_nr;
00935             det_nr = (ifu_nr - 1)/KMOS_IFUS_PER_DETECTOR + 1;
00936 
00937             /* Get subheader data */
00938             header_data[ifu_nr-1] = kmclipm_propertylist_load(fn_obj, det_nr);
00939             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
00940             kmclipm_update_property_string(header_data[ifu_nr-1],
00941                     EXTNAME, extname, "FITS extension name");
00942             cpl_free(extname);
00943 
00944             if (arm_name_struct->name_ids[ifu_nr-1+sf*KMOS_NR_IFUS] >= 1) {
00945                 // IFU is valid
00946 
00947                 /* Fill sky_as_object_frame, do_sky_subtraction and sky_frame */
00948                 sky_as_object_frame = NULL ;
00949                 if ((arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1] != NO_CORRESPONDING_SKYFRAME) && !no_subtract) {
00950                     do_sky_subtraction = TRUE;
00951                     if (no_subtract)    sky_frame = NULL;
00952                     else                sky_frame = 
00953                 arm_name_struct->obj_sky_struct->table[sf].skyFrames[ifu_nr-1];
00954 
00955                     if (sky_tweak){
00956                         sky_as_object_frame = sky_frame;
00957                         sky_frame = NULL;
00958                         sky_ifu_nr = arm_name_struct->obj_sky_struct->table[sf].skyIfus[ifu_nr-1];
00959                     }
00960                 } else {
00961                     do_sky_subtraction = FALSE;
00962                     sky_frame = NULL;
00963                 }
00964 
00965                 /* Get filter and setup grid definition using WAVE_BAND */
00966                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, det_nr, 
00967                         IFU_FILTID_POSTFIX);
00968                 filter_id = cpl_propertylist_get_string(main_header, keyword);
00969                 cpl_free(keyword); 
00970 
00971                 if (print_once) cpl_msg_set_level(CPL_MSG_WARNING);
00972                 print_once = TRUE;
00973 
00974                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0);
00975                 kmclipm_setup_grid_band_lcal(&gd, filter_id, band_table);
00976                 cpl_table_delete(band_table);
00977 
00978                 cpl_msg_set_level(actual_msg_level);
00979 
00980                 /* calc WCS & update subheader */
00981                 kmo_calc_wcs_gd(main_header, header_data[ifu_nr-1], ifu_nr, gd);
00982 
00983                 /* Update some keywords  */
00984                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS, 3, 
00985                         "number of data axes");
00986                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS1, 
00987                         gd.x.dim, "length of data axis 1");
00988                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS2, 
00989                         gd.y.dim, "length of data axis 2");
00990                 kmclipm_update_property_int(header_data[ifu_nr-1], NAXIS3, 
00991                         gd.l.dim, "length of data axis 3");
00992 
00993                 /* Option save_interim only applies if sky_tweak is used */
00994                 if (save_interims && sky_as_object_frame != NULL) {
00995                     header_tmp = kmclipm_propertylist_load(
00996                             cpl_frame_get_filename(sky_as_object_frame), 0);
00997                             
00998                     header_sky[ifu_nr-1]=kmclipm_propertylist_load(
00999                             cpl_frame_get_filename(sky_as_object_frame),det_nr);
01000                     extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
01001                     kmclipm_update_property_string(header_sky[ifu_nr-1], 
01002                             EXTNAME, extname, "FITS extension name");
01003                     cpl_free(extname);
01004 
01005                     kmo_calc_wcs_gd(header_tmp, header_sky[ifu_nr-1], 
01006                             ifu_nr, gd);
01007                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS, 3,
01008                             "number of data axes");
01009                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS1, 
01010                             gd.x.dim, "length of data axis 1");
01011                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS2, 
01012                             gd.y.dim, "length of data axis 2");
01013                     kmclipm_update_property_int(header_sky[ifu_nr-1], NAXIS3, 
01014                             gd.l.dim, "length of data axis 3");
01015                     cpl_propertylist_delete(header_tmp); 
01016                 }
01017 
01018                 /* OH lines based lambda correction */
01019                 oh_lcorr_coeffs = NULL ;
01020                 if (ref_spectrum_frame != NULL) {
01021                     if (kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
01022                             bounds[2*(ifu_nr-1)+1],
01023                             arm_name_struct->obj_sky_struct->table[sf].objFrame,
01024                             SCIENCE, NULL, NULL, flat_frame, xcal_frame,
01025                             ycal_frame, lcal_frame, NULL, NULL, &gd, &tmp_cube1,
01026                             &tmp_cube2, FALSE, FALSE, xcal_interpolation, 
01027                             oscan) == CPL_ERROR_NONE) {
01028                         oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1, 
01029                                 header_data[ifu_nr-1], ref_spectrum_frame, gd,
01030                                 filter_id, ifu_nr);
01031                         cpl_imagelist_delete(tmp_cube1); 
01032                         cpl_imagelist_delete(tmp_cube2); 
01033                     }
01034                 }
01035 
01036                 /* Reconstruct object */
01037                 kmo_reconstruct_sci(ifu_nr, bounds[2*(ifu_nr-1)],
01038                         bounds[2*(ifu_nr-1)+1],
01039                         arm_name_struct->obj_sky_struct->table[sf].objFrame,
01040                         SCIENCE, sky_frame, SCIENCE, flat_frame, xcal_frame,
01041                         ycal_frame, lcal_frame, oh_lcorr_coeffs, velo_corr_ptr,
01042                         &gd, &cube_data[ifu_nr-1], &cube_noise[ifu_nr-1], flux,
01043                         background, xcal_interpolation, oscan);
01044                         
01045                 if (oh_lcorr_coeffs != NULL) 
01046                     cpl_polynomial_delete(oh_lcorr_coeffs); 
01047 
01048                 if (cpl_error_get_code() != CPL_ERROR_NONE) {
01049                     kmo_free_unused_ifus(unused_ifus_after);
01050                     cpl_free(bounds);
01051                     kmo_delete_armNameStruct(arm_name_struct);
01052                     for (j=0 ; j<ifu_nr-1  ; j++) {
01053                         if (cube_data[j] != NULL) 
01054                             cpl_imagelist_delete(cube_data[j]); 
01055                         if (cube_noise[j] != NULL) 
01056                             cpl_imagelist_delete(cube_noise[j]);
01057                         cpl_propertylist_delete(header_data[j]);
01058                         cpl_propertylist_delete(header_noise[j]);
01059                         if (save_interims) {
01060                             cpl_imagelist_delete(cube_interim_object[j]);
01061                             cpl_imagelist_delete(cube_interim_sky[j]);
01062                             cpl_propertylist_delete(header_sky[j]);
01063                         }
01064                     }
01065                     cpl_propertylist_delete(header_data[ifu_nr-1]);
01066                     cpl_free(cube_data) ;
01067                     cpl_free(cube_noise) ;
01068                     cpl_free(header_data) ;
01069                     cpl_free(header_noise) ;
01070                     if (save_interims) {
01071                         cpl_free(cube_interim_object) ;
01072                         cpl_free(cube_interim_sky) ;
01073                         cpl_free(header_sky) ;
01074                     }
01075                     cpl_msg_error(__func__, "Cannot reconstruct");
01076                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01077                     return -1 ;
01078                 }
01079 
01080                 /* If sky_tweak is set, reconstruct sky frame as object */
01081                 /* use kmos_priv_sky_tweak to subtract a modified sky cube */
01082                 if (do_sky_subtraction && sky_tweak) {
01083 
01084                     /* OH lines based lambda correction */
01085                     oh_lcorr_coeffs = NULL ;
01086                     if (ref_spectrum_frame != NULL) {
01087                         if (kmo_reconstruct_sci(sky_ifu_nr,
01088                                     bounds[2*(sky_ifu_nr-1)],
01089                                     bounds[2*(sky_ifu_nr-1)+1], 
01090                                     sky_as_object_frame, SCIENCE, NULL, NULL, 
01091                                     flat_frame, xcal_frame, ycal_frame, 
01092                                     lcal_frame, NULL, NULL, &gd, &tmp_cube1, 
01093                                     &tmp_cube2, FALSE, FALSE, 
01094                                     xcal_interpolation, 
01095                                     oscan) == CPL_ERROR_NONE) {
01096                             oh_lcorr_coeffs = kmo_lcorr_get(tmp_cube1,
01097                                     header_data[ifu_nr-1], ref_spectrum_frame, 
01098                                     gd, filter_id, ifu_nr);
01099                             cpl_imagelist_delete(tmp_cube1);
01100                             cpl_imagelist_delete(tmp_cube2); 
01101                         }
01102                     }
01103 
01104                     /* Reconstruct object */
01105                     kmo_reconstruct_sci(sky_ifu_nr, 
01106                             bounds[2*(sky_ifu_nr-1)], 
01107                             bounds[2*(sky_ifu_nr-1)+1], sky_as_object_frame,
01108                             SCIENCE, sky_frame, SCIENCE, flat_frame,
01109                             xcal_frame, ycal_frame, lcal_frame, oh_lcorr_coeffs,
01110                             velo_corr_ptr, &gd, &tmp_cube1, &tmp_cube2,
01111                             flux, background, xcal_interpolation, oscan);
01112                             
01113                     cpl_imagelist_delete(tmp_cube2); 
01114                     if (oh_lcorr_coeffs != NULL) 
01115                         cpl_polynomial_delete(oh_lcorr_coeffs);
01116                    
01117                     if (save_interims && (sky_as_object_frame != NULL)) {
01118                         cube_interim_object[ifu_nr-1]=
01119                             cpl_imagelist_duplicate(cube_data[ifu_nr-1]);
01120                         cube_interim_sky[ifu_nr-1]=
01121                             cpl_imagelist_duplicate(tmp_cube1);
01122                     }
01123 
01124                     /* Apply the SKY tweaking */
01125                     tmp_cube2 = kmos_priv_sky_tweak(cube_data[ifu_nr-1], 
01126                             tmp_cube1,header_data[ifu_nr-1], .3, tbsub,
01127                             ifu_nr, discard_subband);
01128                     cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01129                     cpl_imagelist_delete(tmp_cube1); 
01130                     cube_data[ifu_nr-1] = tmp_cube2 ;
01131                 } 
01132 
01133                 /* Maintain flux constant in case the pixscale is diff */
01134                 /* For example, pixscale=0.1 => images 28x28 => scaling=4 */
01135                 tmpImg = cpl_imagelist_get(cube_data[ifu_nr-1], 0);
01136                 scaling = (cpl_image_get_size_x(tmpImg) *
01137                         cpl_image_get_size_y(tmpImg)) / 
01138                     (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01139                 cpl_imagelist_divide_scalar(cube_data[ifu_nr-1], scaling);
01140                 if (cube_noise[ifu_nr-1] != NULL) {
01141                     cpl_imagelist_divide_scalar(cube_noise[ifu_nr-1], scaling);
01142                 }
01143 
01144                 /* Divide cube by telluric correction */
01145                 qc_output_unit[ifu_nr-1] = 0 ;
01146                 if (nb_telluric > 0) {
01147                     /* Create the mapping string */
01148                     if (mapping_id == 0) {
01149                         /* Get object name */
01150                         keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX, 
01151                                 ifu_nr, IFU_NAME_POSTFIX);
01152                         tmp_str = cpl_propertylist_get_string(
01153                                 header_data[ifu_nr-1], keyword);
01154                         cpl_free(keyword);
01155                     } else if (mapping_id == 1) {
01156                         tmp_str = "mapping8";
01157                     } else if (mapping_id == 2) {
01158                         tmp_str = "mapping24";
01159                     }
01160 
01161                     /* Check if the nb of occurences of the object name  */
01162                     /* is the same as the number of found tellurics for */
01163                     /* this object (which can be on different arms) */
01164                     telluric_ok = FALSE;
01165                     for (jj = 0; jj < arm_name_struct->nrNames; jj++) {
01166                         if ((!strcmp(arm_name_struct->names[jj], tmp_str) ||
01167                      !strcmp(arm_name_struct->names[jj], IFUS_USER_DEFINED)) &&
01168             arm_name_struct->telluricCnt[jj] == arm_name_struct->namesCnt[jj]) {
01169                             telluric_ok = TRUE;
01170                             break;
01171                         }
01172                     }
01173 
01174                     if (telluric_ok) {
01175                         telluric_data = kmo_tweak_load_telluric(frameset,
01176                                 ifu_nr, FALSE, no_subtract, &ifu_nr_telluric);
01177                         if (telluric_data != NULL) {
01178                             telluric_frame=kmo_dfs_get_frame(frameset,TELLURIC);
01179                             kmo_init_fits_desc(&desc_telluric);
01180                             desc_telluric=kmo_identify_fits_header(
01181                                     cpl_frame_get_filename(telluric_frame));
01182 
01183                             /* Get the index of the telluric noise */
01184                             idx = kmo_identify_index_desc(desc_telluric,
01185                                     ifu_nr, TRUE);
01186                             if (desc_telluric.sub_desc[idx-1].valid_data) {
01187                                 /* Load noise if present */
01188                                 telluric_noise = kmo_tweak_load_telluric(
01189                                         frameset,ifu_nr, TRUE, no_subtract, 
01190                                         &ifu_nr_telluric);
01191                             } else {
01192                                 telluric_noise = NULL ;
01193                             }
01194                             kmo_free_fits_desc(&desc_telluric);
01195 
01196                             kmo_arithmetic_3D_1D(cube_data[ifu_nr-1], 
01197                                     telluric_data, cube_noise[ifu_nr-1],
01198                                     telluric_noise, "/");
01199                             if (telluric_noise != NULL) 
01200                                 kmclipm_vector_delete(telluric_noise);
01201                             kmclipm_vector_delete(telluric_data);
01202 
01203                             /* Convert to ERG if zpoint available */
01204                             zpoint = kmos_sci_red_get_zpoint(telluric_frame,
01205                                     ifu_nr_telluric) ;
01206                             if (zpoint > 0.0) {
01207                                 f_0 = kmos_sci_red_get_f0(filter_id, gd.l.dim,
01208                                         gd.l.start, gd.l.delta) ; 
01209                                 if (f_0 > 0.0) {
01210                                     conversion = f_0*pow(10,-0.4*zpoint)/10.0 ;
01211                                     cpl_msg_info(__func__, 
01212                                 "Apply Unit conversion factor %g for IFU nb %d",
01213                                             conversion, ifu_nr) ;
01214                                     kmo_arithmetic_3D_scalar(
01215                                             cube_data[ifu_nr-1], conversion, 
01216                                             cube_noise[ifu_nr-1], "*") ;
01217                                     qc_output_unit[ifu_nr-1] = 1 ;
01218                                 }
01219                             }
01220                         }
01221                     }
01222                 }
01223 
01224                 /* Divide cube by illumination correction */
01225                 if (nb_illum_corr > 0) {
01226                     illum_data = kmo_dfs_load_image(frameset, ILLUM_CORR,
01227                             ifu_nr, FALSE, FALSE, NULL);
01228                     illum_noise = kmo_dfs_load_image(frameset, ILLUM_CORR, 
01229                             ifu_nr, TRUE, FALSE, NULL);
01230                     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01231                         cpl_msg_warning(__func__,
01232                         "No illumination correction for IFU %d available! "
01233                                         "Proceeding anyway.", ifu_nr);
01234                         if (illum_data != NULL) cpl_image_delete(illum_data);
01235                         if (illum_noise != NULL) cpl_image_delete(illum_noise);
01236                         cpl_error_reset();
01237                     } else {
01238                         kmo_arithmetic_3D_2D(cube_data[ifu_nr-1], illum_data,
01239                                 cube_noise[ifu_nr-1], illum_noise, "/");
01240                         cpl_image_delete(illum_data); 
01241                         cpl_image_delete(illum_noise);
01242                     }
01243                 }
01244             }
01245 
01246             /* Duplicate subheader data */
01247             header_noise[ifu_nr-1] = cpl_propertylist_duplicate(
01248                     header_data[ifu_nr-1]);
01249             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
01250             kmclipm_update_property_string(header_noise[ifu_nr-1], EXTNAME, 
01251                     extname, "FITS extension name");
01252             cpl_free(extname);
01253         } 
01254         cpl_propertylist_delete(main_header) ;
01255 
01256         /* Convert from ADU->ADU/sec by dividing by DIT */
01257         plist = cpl_propertylist_load(cpl_frame_get_filename(
01258                     arm_name_struct->obj_sky_struct->table[sf].objFrame), 0);
01259         dit = kmos_pfits_get_dit(plist) ;
01260         cpl_propertylist_delete(plist) ;
01261         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01262             /* Data / DIT */
01263             if (cube_data[ifu_nr-1] != NULL) {
01264                 kmo_arithmetic_3D_scalar(cube_data[ifu_nr-1], dit, 
01265                         cube_noise[ifu_nr-1], "/") ;
01266             }
01267         }
01268 
01269         /* Count number of reconstructed data- and noise-cubes */
01270         for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01271             if (cube_data[ifu_nr-1] != NULL)    cube_counter_data++;
01272             if (cube_noise[ifu_nr-1] != NULL)   cube_counter_noise++;
01273         }
01274 
01275         /* Save reconstructed cubes of science frame */
01276         if (cube_counter_data > 0) {
01277             cpl_msg_info(__func__, "   > saving...");
01278 
01279             if (!suppress_extension) {
01280                 fn_out = fn_obj;
01281 
01282                 int nr_found = 0;
01283                 // remove any path-elements from filename and use it as suffix
01284                 split = kmo_strsplit(fn_out, "/", &nr_found);
01285                 fn_suffix = cpl_sprintf("_%s", split[nr_found-1]);
01286                 kmo_strfreev(split);
01287 
01288                 // remove '.fits' at the end if there is any
01289                 char *fff = fn_suffix;
01290                 fff += strlen(fn_suffix)-5;
01291                 if (strcmp(fff, ".fits") == 0) {
01292                     fn_suffix[strlen(fn_suffix)-5] = '\0';
01293                 }
01294             } else {
01295                 fn_suffix = cpl_sprintf("_%d", suppress_index++);
01296             }
01297 
01298             fn_out = RECONSTRUCTED_CUBE;
01299 
01300             /* Create Primary Header */
01301             kmo_dfs_save_main_header(frameset, fn_out, fn_suffix,
01302                     arm_name_struct->obj_sky_struct->table[sf].objFrame, NULL,
01303                     parlist, cpl_func);
01304             /* save intermediate products (only in sky tweak case) */
01305             if (save_interims && (sky_as_object_frame != NULL)) {
01306                 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_CUBE, 
01307                         fn_suffix,
01308                         arm_name_struct->obj_sky_struct->table[sf].objFrame, 
01309                         NULL, parlist, cpl_func);
01310                 kmo_dfs_save_main_header(frameset, INTERIM_OBJECT_SKY, 
01311                         fn_suffix,
01312                         arm_name_struct->obj_sky_struct->table[sf].objFrame,
01313                         NULL, parlist, cpl_func);
01314             }
01315 
01316             /* Loop on IFUs */
01317             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01318                 
01319                 /* Hold the QC */
01320                 if (qc_output_unit[ifu_nr-1] == 0) 
01321                     kmclipm_update_property_string(header_data[ifu_nr-1], 
01322                             "ESO QC CUBE_UNIT", "ADU/sec", "Cube Unit");
01323                 else 
01324                     kmclipm_update_property_string(header_data[ifu_nr-1], 
01325                             "ESO QC CUBE_UNIT", "ERG/sec/cm2/A", "Cube Unit");
01326 
01327                 /* Save data Extension */
01328                 kmo_dfs_save_cube(cube_data[ifu_nr-1], fn_out, fn_suffix, 
01329                         header_data[ifu_nr-1], 0./0.);
01330                 cpl_imagelist_delete(cube_data[ifu_nr-1]); 
01331 
01332                 /* Save noise Extension */
01333                 if (cube_counter_noise > 0) {
01334                     kmo_dfs_save_cube(cube_noise[ifu_nr-1], fn_out, fn_suffix,
01335                             header_noise[ifu_nr-1], 0./0.);
01336                 }
01337                 cpl_propertylist_delete(header_noise[ifu_nr-1]);
01338                 cpl_imagelist_delete(cube_noise[ifu_nr-1]);
01339 
01340                 /* save intermediate products (only in sky tweak case */
01341                 if (save_interims && (sky_as_object_frame != NULL)) {
01342                     kmo_dfs_save_cube(cube_interim_object[ifu_nr-1],
01343                             INTERIM_OBJECT_CUBE, fn_suffix,
01344                             header_data[ifu_nr-1], 0./0.);
01345                     kmo_dfs_save_cube(cube_interim_sky[ifu_nr-1], 
01346                             INTERIM_OBJECT_SKY, fn_suffix, header_sky[ifu_nr-1],
01347                             0./0.);
01348                 }
01349                 cpl_propertylist_delete(header_data[ifu_nr-1]);
01350                 if (save_interims) {
01351                     cpl_imagelist_delete(cube_interim_object[ifu_nr-1]);
01352                     cpl_imagelist_delete(cube_interim_sky[ifu_nr-1]);
01353                     cpl_propertylist_delete(header_sky[ifu_nr-1]);
01354                 }
01355             } 
01356             cpl_free(fn_suffix);
01357         } else {
01358             cpl_msg_info(__func__, "   > all IFUs invalid, don't save");
01359             for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01360                 cpl_propertylist_delete(header_data[ifu_nr-1]); 
01361                 cpl_propertylist_delete(header_noise[ifu_nr-1]); 
01362             }
01363         }
01364         cpl_free(qc_output_unit) ;
01365     } 
01366     cpl_free(bounds) ;
01367     cpl_free(cube_data);  
01368     cpl_free(cube_noise);
01369     cpl_free(header_data); 
01370     cpl_free(header_noise); 
01371     if (save_interims) {
01372         cpl_free(cube_interim_object);  
01373         cpl_free(cube_interim_sky);     
01374         cpl_free(header_sky);          
01375     }
01376 
01377     kmo_print_unused_ifus(unused_ifus_after, TRUE);
01378     kmo_free_unused_ifus(unused_ifus_after);
01379 
01380     /* Combine */
01381     suppress_index = 0;
01382     if (!no_combine) {
01383         cpl_msg_info(__func__, "Combining reconstructed objects");
01384         if (mapping_id==0 || (mapping_id>0 && (strcmp(ifus_txt, "") || 
01385                         strcmp(name,"")))){
01386             /* Loop all available objects */
01387             for (i = 0; i < arm_name_struct->nrNames; i++) {
01388                 cpl_msg_info(__func__, 
01389                         "   > object: %s", arm_name_struct->names[i]);
01390                 nr_data = arm_name_struct->namesCnt[i];
01391                 cube_data=(cpl_imagelist**)cpl_calloc(nr_data, 
01392                         sizeof(cpl_imagelist*));
01393                 cube_noise=(cpl_imagelist**)cpl_calloc(nr_data, 
01394                         sizeof(cpl_imagelist*));
01395                 header_data=(cpl_propertylist**)cpl_calloc(nr_data,
01396                         sizeof(cpl_propertylist*));
01397                 header_noise=(cpl_propertylist**)cpl_calloc(nr_data,
01398                         sizeof(cpl_propertylist*));
01399 
01400                 /* Initialise */
01401                 for (jj = 0; jj < nr_data; jj++) {
01402                     cube_data[jj] = NULL ; 
01403                     cube_noise[jj] = NULL ; 
01404                     header_data[jj] = NULL ; 
01405                     header_noise[jj] = NULL ; 
01406                 }
01407 
01408                 // setup cube-list and header-list for kmo_priv_combine()
01409                 cube_counter_data = 0;
01410                 cube_counter_noise = 0;
01411                 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01412                 while (tmp_frame != NULL ) {
01413                     fn_reconstr = cpl_frame_get_filename(tmp_frame);
01414                     main_header = kmclipm_propertylist_load(fn_reconstr, 0);
01415                     
01416                     kmo_init_fits_desc(&desc1);
01417                     desc1 = kmo_identify_fits_header(fn_reconstr);
01418 
01419                    for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01420                         // check if object-name equals the one in our list
01421                         keyword = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX, ifu_nr,
01422                                 IFU_NAME_POSTFIX);
01423                         tmp_str=cpl_propertylist_get_string(main_header,
01424                                 keyword);
01425                         cpl_free(keyword);
01426 
01427                         if (!strcmp(arm_name_struct->names[i],tmp_str) || 
01428                         !strcmp(arm_name_struct->names[i], IFUS_USER_DEFINED)) {
01429                             /* Found object-IFU with matching name */
01430                             /* Load data & subheader */
01431                             idx=kmo_identify_index(fn_reconstr,ifu_nr,FALSE);
01432 
01433                             if (desc1.sub_desc[idx-1].valid_data) {
01434                                 cube_data[cube_counter_data] =
01435                                     kmclipm_imagelist_load(fn_reconstr,
01436                                             CPL_TYPE_FLOAT, idx);
01437     /* Set cubes borders (1 pixel) to Nan to avoid jumps in combined cube */
01438                                 if (edge_nan) {
01439                                     kmo_edge_nan(cube_data[cube_counter_data], 
01440                                             ifu_nr);
01441                                 }
01442 
01443                                 header_data[cube_counter_data] =
01444                                     kmclipm_propertylist_load(fn_reconstr, 
01445                                             idx);
01446                                 cpl_propertylist_update_string(
01447                                         header_data[cube_counter_data],
01448                                         "ESO PRO FRNAME", fn_reconstr);
01449                                 cpl_propertylist_update_int(
01450                                         header_data[cube_counter_data],
01451                                         "ESO PRO IFUNR", ifu_nr);
01452                                 cube_counter_data++;
01453                             }
01454 
01455                             /* Load noise & subheader (if existing) */
01456                             if (desc1.ex_noise) {
01457                                 idx = kmo_identify_index(fn_reconstr, ifu_nr, 
01458                                         TRUE);
01459                                 if (desc1.sub_desc[idx-1].valid_data) {
01460                                     cube_noise[cube_counter_noise] =
01461                                         kmclipm_imagelist_load(fn_reconstr, 
01462                                                 CPL_TYPE_FLOAT, idx);
01463                                     if (edge_nan) {
01464                                         kmo_edge_nan(
01465                                                 cube_noise[cube_counter_noise],
01466                                                 ifu_nr);
01467                                     }
01468                                     header_noise[cube_counter_noise] =
01469                                         kmclipm_propertylist_load(fn_reconstr, 
01470                                                 idx);
01471                                     cube_counter_noise++;
01472                                 }
01473                             }
01474                             cpl_error_reset();
01475                         }
01476                     }
01477                     kmo_free_fits_desc(&desc1);
01478                     cpl_propertylist_delete(main_header);
01479                     tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01480                 } 
01481 
01482                 if (cube_counter_noise == 0) {
01483                     cpl_free(cube_noise);
01484                     cube_noise = NULL ; 
01485                 }
01486 
01487                 if (cube_counter_data > 1) {
01488                     if (cube_counter_data == cube_counter_noise ||
01489                             cube_counter_noise == 0) {
01490                         kmo_priv_combine(cube_data, cube_noise, header_data,
01491                                 header_noise, cube_counter_data,
01492                                 cube_counter_noise, arm_name_struct->names[i],
01493                                 "", comb_method, smethod, fmethod, filename,
01494                                 cmethod, cpos_rej, cneg_rej, citer, cmin, cmax,
01495                                 extrapol_enum, flux, &combined_data,
01496                                 &combined_noise, &exp_mask);
01497                     } else {
01498                         cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
01499                         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01500                         return -1 ;
01501                     }
01502                 } else if (cube_counter_data == 1) {
01503                     cpl_msg_warning(__func__, 
01504                             "Only one reconstructed cube with this object");
01505                     combined_data = cpl_imagelist_duplicate(cube_data[0]);
01506                     tmpImg = cpl_imagelist_get(combined_data, 0);
01507                     exp_mask = cpl_image_new(cpl_image_get_size_x(tmpImg),
01508                             cpl_image_get_size_y(tmpImg), CPL_TYPE_FLOAT);
01509                     kmo_image_fill(exp_mask, 1.);
01510 
01511                     combined_noise = NULL ;
01512                     if (cube_counter_noise > 0 && cube_noise[0] != NULL) {
01513                         combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
01514                     }
01515                 } else {
01516                     cpl_msg_error(__func__, "No cube found with this obj name");
01517                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01518                     return -1 ;
01519                 } 
01520                 for (jj = 0; jj < nr_data; jj++) {
01521                     cpl_imagelist_delete(cube_data[jj]); 
01522                     if (cube_counter_noise > 0) 
01523                         cpl_imagelist_delete(cube_noise[jj]); 
01524                 }
01525                 cpl_free(cube_data); 
01526                 cpl_free(cube_noise);
01527  
01528                 fn_out = COMBINED_CUBE;
01529                 if (!suppress_extension) {
01530                     char tmp_suffix[1024];
01531                     tmp_suffix[0] = '\0';
01532 
01533                     if (arm_name_struct->telluricCnt[i] == 
01534                             arm_name_struct->namesCnt[i]) {
01535                         strcat(tmp_suffix, "_telluric");
01536                     }
01537                     if (nb_illum_corr > 0)  strcat(tmp_suffix, "_illum");
01538                     if (sky_tweak)          strcat(tmp_suffix, "_skytweak");
01539 
01540                     if (strlen(tmp_suffix) > 0) {
01541                         fn_suffix = cpl_sprintf("_%s_%s", 
01542                                 arm_name_struct->names[i], tmp_suffix);
01543                     } else {
01544                         fn_suffix = cpl_sprintf("_%s", 
01545                                 arm_name_struct->names[i]);
01546                     }
01547                 } else {
01548                     fn_suffix = cpl_sprintf("_%d", suppress_index++);
01549                 }
01550 
01551                 // save combined cube
01552                 tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01553                 kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, 
01554                         tmp_frame, NULL, parlist, cpl_func);
01555                 kmo_dfs_save_main_header(frameset, EXP_MASK, fn_suffix, 
01556                         tmp_frame, NULL, parlist, cpl_func);
01557                 kmo_dfs_save_cube(combined_data, fn_out, fn_suffix, 
01558                         header_data[0], 0./0.);
01559                 kmo_dfs_save_image(exp_mask, EXP_MASK, fn_suffix, 
01560                         header_data[0], 0./0.);
01561                 cpl_image_delete(exp_mask);
01562                     
01563                 if (header_noise[0] == NULL) {
01564                     header_noise[0]=cpl_propertylist_duplicate(header_data[0]);
01565                     tmp_str=cpl_propertylist_get_string(header_data[0],EXTNAME);
01566                     kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
01567                     extname = kmo_extname_creator(ifu_frame, tmp_int,EXT_NOISE);
01568                     kmclipm_update_property_string(header_noise[0], EXTNAME, 
01569                             extname, "FITS extension name");
01570                     cpl_free(extname);
01571                 }
01572                 kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix, 
01573                         header_noise[0], 0./0.);
01574 
01575                 cpl_free(fn_suffix);
01576                 for (jj = 0; jj < nr_data; jj++) {
01577                     cpl_propertylist_delete(header_data[jj]); 
01578                     cpl_propertylist_delete(header_noise[jj]); 
01579                 }
01580                 cpl_free(header_data);
01581                 cpl_free(header_noise);
01582                 cpl_imagelist_delete(combined_data);
01583                 if (combined_noise != NULL)
01584                     cpl_imagelist_delete(combined_noise);
01585             } 
01586         } else {
01587             /* Mapping_mode */
01588             nr_data = KMOS_NR_IFUS * 
01589                 cpl_frameset_count_tags(frameset,RECONSTRUCTED_CUBE);
01590             cube_data = (cpl_imagelist**)cpl_calloc(nr_data, 
01591                     sizeof(cpl_imagelist*));
01592             cube_noise = (cpl_imagelist**)cpl_calloc(nr_data, 
01593                     sizeof(cpl_imagelist*));
01594             header_data=(cpl_propertylist**)cpl_calloc(nr_data, 
01595                     sizeof(cpl_propertylist*));
01596             header_noise=(cpl_propertylist**)cpl_calloc(nr_data, 
01597                     sizeof(cpl_propertylist*));
01598 
01599             /* Initialise */
01600             for (jj = 0; jj < nr_data; jj++) {
01601                 cube_data[jj] = NULL ; 
01602                 cube_noise[jj] = NULL ; 
01603                 header_data[jj] = NULL ; 
01604                 header_noise[jj] = NULL ; 
01605             }
01606 
01607             cube_counter_data = 0;
01608             cube_counter_noise = 0;
01609             tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01610             while (tmp_frame != NULL ) {
01611                 fn_reconstr = cpl_frame_get_filename(tmp_frame);
01612 
01613                 kmo_init_fits_desc(&desc1);
01614                 desc1 = kmo_identify_fits_header(fn_reconstr);
01615                 for (ifu_nr = 1; ifu_nr <= KMOS_NR_IFUS; ifu_nr++) {
01616                     idx = kmo_identify_index(fn_reconstr, ifu_nr, FALSE);
01617 
01618                     if (desc1.sub_desc[idx-1].valid_data) {
01619                         cpl_msg_debug(__func__, 
01620                                 "Load in cube_data - Frame: %s IFU: %d",
01621                                 fn_reconstr, ifu_nr) ;
01622                         cube_data[cube_counter_data] = kmclipm_imagelist_load(
01623                                 fn_reconstr, CPL_TYPE_FLOAT, idx);
01624                         if (edge_nan) 
01625                             kmo_edge_nan(cube_data[cube_counter_data], ifu_nr);
01626 
01627                         if (fast_mode) {
01628                             tmpImg = cpl_imagelist_collapse_median_create(
01629                                     cube_data[cube_counter_data]);
01630                             tmp_cube1 = cpl_imagelist_new();
01631                             cpl_imagelist_set(tmp_cube1, tmpImg, 0);
01632                             cpl_imagelist_delete(cube_data[cube_counter_data]);
01633                             cube_data[cube_counter_data] = tmp_cube1;
01634                         }
01635 
01636                         cpl_msg_debug(__func__, 
01637                                 "Load in header_data - Frame: %s IFU: %d",
01638                                 fn_reconstr, ifu_nr) ;
01639                         header_data[cube_counter_data] = 
01640                             kmclipm_propertylist_load(fn_reconstr, idx);
01641                         cpl_propertylist_update_string(
01642                                 header_data[cube_counter_data], 
01643                                 "ESO PRO FRNAME", fn_reconstr);
01644                         cpl_propertylist_update_int(
01645                                 header_data[cube_counter_data], 
01646                                 "ESO PRO IFUNR", ifu_nr);
01647                         cube_counter_data++;
01648                         cpl_msg_debug(__func__, "cube_counter_data: %d\n", 
01649                             cube_counter_data) ;
01650                     }
01651 
01652                     /* Load noise & subheader (if existing) */
01653                     if (desc1.ex_noise) {
01654                         idx = kmo_identify_index(fn_reconstr,ifu_nr,TRUE);
01655                         if (desc1.sub_desc[idx-1].valid_data) {
01656                             cpl_msg_debug(__func__, 
01657                                     "Load in cube_noise - Frame: %s IFU: %d",
01658                                     fn_reconstr, ifu_nr) ;
01659                             cube_noise[cube_counter_noise] =
01660                                 kmclipm_imagelist_load(fn_reconstr, 
01661                                         CPL_TYPE_FLOAT, idx);
01662 
01663                             if (edge_nan) 
01664                                 kmo_edge_nan(cube_noise[cube_counter_noise],
01665                                         ifu_nr);
01666                             if (fast_mode) {
01667                                 tmpImg=cpl_imagelist_collapse_median_create(
01668                                         cube_noise[cube_counter_noise]);
01669                                 tmp_cube1 = cpl_imagelist_new();
01670                                 cpl_imagelist_set(tmp_cube1, tmpImg, 0);
01671                                 cpl_imagelist_delete(
01672                                         cube_noise[cube_counter_noise]);
01673                                 cube_noise[cube_counter_noise] = tmp_cube1;
01674                             }
01675                             cpl_msg_debug(__func__, 
01676                                     "Load in header_noise - Frame: %s IFU: %d",
01677                                     fn_reconstr, ifu_nr) ;
01678                             header_noise[cube_counter_noise] = 
01679                                 kmclipm_propertylist_load(fn_reconstr, idx);
01680                             cube_counter_noise++;
01681                             cpl_msg_debug(__func__, "cube_counter_noise: %d\n", 
01682                                 cube_counter_noise) ;
01683                         }
01684                     }
01685                     cpl_error_reset();
01686                 } 
01687                 kmo_free_fits_desc(&desc1);
01688                 tmp_frame = kmo_dfs_get_frame(frameset, NULL);
01689             }
01690    
01691             if (cube_counter_noise == 0) {
01692                 cpl_free(cube_noise);
01693                 cube_noise = NULL ; 
01694             }
01695 
01696             if (cube_counter_data > 1) {
01697                 if (cube_counter_data == cube_counter_noise ||
01698                         cube_counter_noise == 0) {
01699                     kmo_priv_combine(cube_data, cube_noise, header_data,
01700                             header_noise, cube_counter_data, cube_counter_noise,
01701                             mapping_mode, "", comb_method, smethod, fmethod,
01702                             filename, cmethod, cpos_rej, cneg_rej, citer, cmin,
01703                             cmax, extrapol_enum, flux, &combined_data, 
01704                             &combined_noise, NULL);
01705                 } else {
01706                     cpl_msg_error(__func__, "Data/Noise cubes nb mismatch");
01707                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01708                     return -1 ;
01709                 }
01710             } else {
01711                 cpl_msg_warning(__func__, 
01712                         "There is only one reconstructed cube - Save it");
01713                 combined_data = cpl_imagelist_duplicate(cube_data[0]);
01714 
01715                 if (cube_noise[0] != NULL) {
01716                     combined_noise = cpl_imagelist_duplicate(cube_noise[0]);
01717                 }
01718             }
01719             fn_out = COMBINED_CUBE;
01720             fn_suffix = cpl_sprintf("_%s", mapping_mode);
01721 
01722             // save combined cube
01723             tmp_frame = kmo_dfs_get_frame(frameset, RECONSTRUCTED_CUBE);
01724             kmo_dfs_save_main_header(frameset, fn_out, fn_suffix, tmp_frame, 
01725                     NULL, parlist, cpl_func);
01726             kmo_dfs_save_cube(combined_data, fn_out, fn_suffix, header_data[0],
01727                     0./0.);
01728 
01729             if (cube_counter_noise == 0) {
01730                 header_noise[0] = cpl_propertylist_duplicate(header_data[0]);
01731                 tmp_str = cpl_propertylist_get_string(header_data[0], EXTNAME);
01732                 kmo_extname_extractor(tmp_str, &ft, &tmp_int, content);
01733                 extname = kmo_extname_creator(ifu_frame, tmp_int, EXT_NOISE);
01734                 kmclipm_update_property_string(header_noise[0], EXTNAME,
01735                         extname, "FITS extension name");
01736                 cpl_free(extname);
01737             }
01738             kmo_dfs_save_cube(combined_noise, fn_out, fn_suffix, 
01739                     header_noise[0], 0./0.);
01740             
01741             if (cube_counter_noise == 0) 
01742                 cpl_propertylist_delete(header_noise[0]); 
01743             cpl_free(fn_suffix);
01744             for (i = 0; i < cube_counter_data ; i++) {
01745                 cpl_propertylist_delete(header_data[i]); 
01746                 cpl_imagelist_delete(cube_data[i]);
01747             }
01748             for (i = 0; i < cube_counter_noise ; i++) {
01749                 cpl_propertylist_delete(header_noise[i]); 
01750                 cpl_imagelist_delete(cube_noise[i]); 
01751             }
01752             cpl_free(cube_data); 
01753             cpl_free(cube_noise);
01754             cpl_free(header_data);
01755             cpl_free(header_noise);
01756             cpl_imagelist_delete(combined_data); 
01757             cpl_imagelist_delete(combined_noise);
01758         }
01759     } 
01760     kmo_delete_armNameStruct(arm_name_struct);
01761 
01762     /* Collapse the reconstructed cubes if requested */
01763     if (collapse_reconstructed) {
01764         kmos_collapse_cubes(RECONSTRUCTED_CUBE, frameset, parlist, 0.1,
01765                 "", DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
01766                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
01767     }
01768  
01769     /* Collapse the combined cubes if requested */
01770     if (collapse_combined) {
01771         kmos_collapse_cubes(COMBINED_CUBE, frameset, parlist, 0.1, "",
01772                 DEF_REJ_METHOD, DEF_POS_REJ_THRES, DEF_NEG_REJ_THRES,
01773                 DEF_ITERATIONS, DEF_NR_MIN_REJ, DEF_NR_MAX_REJ) ;
01774     }
01775     return 0;
01776 }
01777 
01780 /*----------------------------------------------------------------------------*/
01788 /*----------------------------------------------------------------------------*/
01789 static int kmos_sci_red_check_inputs(
01790         cpl_frameset            *   frameset, 
01791         double                      pix_scale,
01792         int                     *   mapping_id)
01793 {
01794     int     nb_science, nb_xcal, nb_ycal, nb_lcal, nb_wave_band,
01795             nb_master_flat, nb_illum_corr, nb_telluric, nb_oh_spec ;
01796     cpl_error_code          err ;
01797     const cpl_frame     *   frame1 ;
01798     const cpl_frame     *   frame2 ;
01799     int                     next1, next2, mapping_id_loc,
01800                             mapping_id_curr, nx, ny ;
01801     cpl_propertylist    *   mh ;
01802     cpl_propertylist    *   eh ;
01803     const char          *   tmp_str ;
01804 
01805     /* Check Entries */
01806     if (frameset == NULL || mapping_id == NULL) return -1;
01807 
01808     /* Count frames */
01809     nb_science = cpl_frameset_count_tags(frameset, SCIENCE) ;
01810     nb_xcal = cpl_frameset_count_tags(frameset, XCAL) ;
01811     nb_ycal = cpl_frameset_count_tags(frameset, YCAL) ;
01812     nb_lcal = cpl_frameset_count_tags(frameset, LCAL) ;
01813     nb_wave_band = cpl_frameset_count_tags(frameset, WAVE_BAND) ;
01814     nb_master_flat = cpl_frameset_count_tags(frameset, MASTER_FLAT);
01815     nb_illum_corr = cpl_frameset_count_tags(frameset, ILLUM_CORR);
01816     nb_telluric = cpl_frameset_count_tags(frameset, TELLURIC);
01817     nb_oh_spec = cpl_frameset_count_tags(frameset, OH_SPEC) ;
01818 
01819     /* Checks  */
01820     if (nb_science < 1) {
01821         cpl_msg_error(__func__, "At least one SCIENCE frame is required") ;
01822         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01823         return 0 ;
01824     }
01825     if (nb_science == 1) {
01826         cpl_msg_warning(__func__, 
01827                 "Only 1 SCIENCE: no sky subtraction - reconstruct all IFUs");
01828     }
01829     if (nb_xcal != 1 || nb_ycal != 1 || nb_lcal != 1) {
01830         cpl_msg_error(__func__, "Exactly 1 XCAL/YCAL/LCAL expected") ;
01831         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01832         return 0 ;
01833     }
01834     if (nb_wave_band != 1) {
01835         cpl_msg_error(__func__, "At most one WAVE_BAND frame expected") ;
01836         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01837         return 0 ;
01838     }
01839     
01840     if (nb_master_flat > 1 || nb_illum_corr > 1 || nb_telluric > 1 ||
01841             nb_oh_spec > 1) {
01842         cpl_msg_error(__func__, 
01843             "MASTER_FLAT/ILLUM_CORR/OH_SPEC/TELLURIC: 0 or 1 frame expected") ;
01844         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01845         return 0 ;
01846     }
01847 
01848     /* filter_id, grating_id and rotator offset match all detectors */
01849     err = CPL_ERROR_NONE ;
01850     err += kmo_check_frameset_setup(frameset, SCIENCE, TRUE, FALSE, TRUE);
01851     err += kmo_check_frame_setup(frameset, SCIENCE, YCAL, TRUE, FALSE, TRUE);
01852     err += kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
01853     err += kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
01854     if (nb_master_flat > 0) err += kmo_check_frame_setup(frameset, XCAL,
01855             MASTER_FLAT, TRUE, FALSE, TRUE);
01856     if (nb_telluric > 0)    err += kmo_check_frame_setup(frameset, XCAL, 
01857             TELLURIC, TRUE, FALSE, TRUE);
01858     if (nb_oh_spec > 0)     err += kmo_check_oh_spec_setup(frameset, XCAL);
01859 
01860     /* Check XCAL */
01861     frame1 = kmo_dfs_get_frame(frameset, XCAL);
01862     next1 = cpl_frame_get_nextensions(frame1);
01863     if (next1 % KMOS_NR_DETECTORS) {
01864         cpl_msg_error(__func__, "XCAL wrong format") ;
01865         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01866         return 0 ;
01867     }
01868     /* Check YCAL */
01869     frame2 = kmo_dfs_get_frame(frameset, YCAL);
01870     next2 = cpl_frame_get_nextensions(frame2);
01871     if (next1 != next2) {
01872         cpl_msg_error(__func__, "YCAL wrong format") ;
01873         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01874         return 0 ;
01875     }
01876     /* Check LCAL */
01877     frame2 = kmo_dfs_get_frame(frameset, LCAL);
01878     next2 = cpl_frame_get_nextensions(frame2);
01879     if (next1 != next2) {
01880         cpl_msg_error(__func__, "LCAL wrong format") ;
01881         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01882         return 0 ;
01883     }
01884     /* Check MASTER_FLAT */
01885     if (nb_master_flat >= 1) {
01886         frame2 = kmo_dfs_get_frame(frameset, MASTER_FLAT);
01887         next2 = cpl_frame_get_nextensions(frame2);
01888         if (next2 % (2*KMOS_NR_DETECTORS)) {
01889             cpl_msg_error(__func__, "MASTER_FLAT wrong format") ;
01890             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01891             return 0 ;
01892         }
01893     }
01894     /* Check ILLUM_CORR */
01895     if (nb_illum_corr >= 1) {
01896         frame2 = kmo_dfs_get_frame(frameset, ILLUM_CORR);
01897         /* Check number of extensions */
01898         next2 = cpl_frame_get_nextensions(frame2);
01899         if (next2 != 24 && next2 != 48) {
01900             cpl_msg_error(__func__, "ILLUM wrong format") ;
01901             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01902             return 0 ;
01903         }
01904         /* Check Size regarding the pixscale */
01905         eh = cpl_propertylist_load(cpl_frame_get_filename(frame2), 1);
01906         nx = kmos_pfits_get_naxis1(eh) ;
01907         ny = kmos_pfits_get_naxis2(eh) ;
01908         cpl_propertylist_delete(eh) ;
01909         if (fabs(nx*pix_scale-2.8) > 1e-3 || fabs(ny*pix_scale-2.8) > 1e-3) {
01910             cpl_msg_error(__func__, 
01911                     "ILLUM wrong Size (nx/y*pix_scale= %g/%g <> 2.8)", 
01912                     nx*pix_scale, ny*pix_scale) ;
01913             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01914             return 0 ;
01915         }
01916     }
01917     /* Check TELLURIC */
01918     if (nb_telluric >= 1) {
01919         frame2 = kmo_dfs_get_frame(frameset, TELLURIC);
01920         next2 = cpl_frame_get_nextensions(frame2);
01921         if (next2 != 24 && next2 != 48) {
01922             cpl_msg_error(__func__, "TELLURIC wrong format") ;
01923             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01924             return 0 ;
01925         }
01926     }
01927     
01928     /* Loop on the SCIENCE frames */
01929     frame2 = kmo_dfs_get_frame(frameset, SCIENCE);
01930     mapping_id_loc = -1 ;
01931     while (frame2 != NULL ) {
01932         next2 = cpl_frame_get_nextensions(frame2);
01933         if (next2 != 3) {
01934             cpl_msg_error(__func__, "SCIENCE wrong format") ;
01935             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01936             return 0 ;
01937         }
01938         
01939         mh = cpl_propertylist_load(cpl_frame_get_filename(frame2), 0);
01940         tmp_str = cpl_propertylist_get_string(mh, TPL_ID);
01941         if (!strcmp(tmp_str, MAPPING8))             mapping_id_curr = 1 ;
01942         else if (strcmp(tmp_str, MAPPING24) == 0)   mapping_id_curr = 2 ;
01943         else                                        mapping_id_curr = 0 ;
01944         cpl_propertylist_delete(mh);
01945         
01946         if (mapping_id_loc < 0)    mapping_id_loc = mapping_id_curr ;
01947         if (mapping_id_curr != mapping_id_loc) {
01948             cpl_msg_error(__func__, "Inconsistent MAPPING information") ;
01949             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01950             return 0 ;
01951         }
01952         frame2 = kmo_dfs_get_frame(frameset, NULL);
01953     }
01954 
01955     /* Verify that XCAL / YCAL were generated together */
01956     err += kmo_check_frame_setup_md5_xycal(frameset);
01957     /* Verify that XCAL and YCAL / LCAL were generated together */
01958     err += kmo_check_frame_setup_md5(frameset);
01959     /* b_start/b_end/b_samples used for LCAL and TELLURIC were the same */
01960     err += kmo_check_frame_setup_sampling(frameset);
01961 
01962     if (err != CPL_ERROR_NONE) {
01963         cpl_msg_warning(__func__, "Frames are inconsistent") ;
01964         return 0 ;
01965     }
01966 
01967     /* Return */
01968     *mapping_id = mapping_id_loc ;
01969     return 1 ;
01970 }
01971 
01972 /*----------------------------------------------------------------------------*/
01979 /*----------------------------------------------------------------------------*/
01980 static double kmos_sci_red_get_zpoint(
01981         cpl_frame   *   frame, 
01982         int             ifu_nr)
01983 {
01984     cpl_propertylist    *   plist ;
01985     double                  zpoint ;
01986     int                     nb_ext, ext_nb ;
01987 
01988     /* Check entries */
01989     if (frame == NULL) return -1.0 ;
01990     if (cpl_error_get_code() != CPL_ERROR_NONE) return -1.0 ;
01991 
01992     /* Get the number of extentions */
01993     nb_ext = cpl_frame_get_nextensions(frame);
01994     
01995     /* Compute ext_nb */
01996     if (nb_ext == KMOS_NR_IFUS)             ext_nb = ifu_nr ;
01997     else if (nb_ext == 2 * KMOS_NR_IFUS)    ext_nb = 2 * ifu_nr - 1 ;
01998     else return -1.0 ;
01999     
02000     /* Get QC ZPOINT */
02001     plist = cpl_propertylist_load(cpl_frame_get_filename(frame), ext_nb);
02002     zpoint = cpl_propertylist_get_double(plist, "ESO QC ZPOINT") ;
02003     cpl_propertylist_delete(plist) ;
02004 
02005     if (cpl_error_get_code() != CPL_ERROR_NONE) {
02006         cpl_error_reset() ;
02007         zpoint = -1.0 ;
02008     }
02009 
02010     return zpoint ;
02011 }
02012  
02013 /*----------------------------------------------------------------------------*/
02019 /*----------------------------------------------------------------------------*/
02020 static double kmos_sci_red_get_f0(
02021         const char      *   filter_id,
02022         int                 lam_dim,
02023         double              lam_start,
02024         double              lam_delta)
02025 {
02026     double  f_0 = -1.0 ;
02027     double cent_wl = lam_start + (lam_delta * (lam_dim/2.0)) ;
02028     if (!strcmp(filter_id, "H"))                    f_0 = 1.133e-9 ;
02029     if (!strcmp(filter_id, "HK") && cent_wl < 1.9)  f_0 = 1.133e-9 ;
02030     if (!strcmp(filter_id, "HK") && cent_wl >= 1.9) f_0 = 4.283e-10 ;
02031     if (!strcmp(filter_id, "K"))                    f_0 = 4.283e-10 ;
02032     if (!strcmp(filter_id, "YJ"))                   f_0 = 3.129e-9 ;
02033     if (!strcmp(filter_id, "IZ"))                   f_0 = 7.63e-9 ;
02034     return f_0 ;
02035 }
02036  
02037 
02038 
02039 int print_warning_once_tweak_std = TRUE;
02040 /*----------------------------------------------------------------------------*/
02065 /*----------------------------------------------------------------------------*/
02066 static kmclipm_vector * kmo_tweak_load_telluric(
02067         cpl_frameset    *   frameset,
02068         int                 ifu_nr,
02069         int                 is_noise,
02070         int                 no_subtract,
02071         int             *   ifu_nr_telluric)
02072 {
02073     kmclipm_vector      *vec                = NULL;
02074     cpl_propertylist    *header             = NULL;
02075     const char          *tplid              = NULL;
02076     int                 actual_msg_level    = 0 ;
02077 
02078 
02079     /* Check entries */
02080     if (frameset == NULL || ifu_nr_telluric == NULL) return NULL ;
02081     if (ifu_nr < 1 || ifu_nr > KMOS_NR_IFUS) return NULL ;
02082 
02083     header = kmo_dfs_load_primary_header(frameset, TELLURIC);
02084     tplid = cpl_propertylist_get_string(header, TPL_ID);
02085     if (!strcmp(tplid, "KMOS_spec_cal_stdstar")) {
02086         if (print_warning_once_tweak_std) {
02087             cpl_msg_warning(__func__,
02088                 "KMOS_spec_cal_stdstar template used => 1 telluric/detector");
02089             print_warning_once_tweak_std = FALSE;
02090         }
02091     }
02092 
02093     *ifu_nr_telluric = kmo_tweak_find_ifu(frameset, ifu_nr);
02094     if (ifu_nr!=*ifu_nr_telluric && *ifu_nr_telluric!=-1 && no_subtract!=-1) {
02095         if (!no_subtract) {
02096             cpl_msg_info(__func__, "Telluric IFU %d selected", 
02097                     *ifu_nr_telluric);
02098         } else {
02099             cpl_msg_info(__func__, "For IFU %d, telluric in IFU %d selected", 
02100                     ifu_nr, *ifu_nr_telluric);
02101         }
02102     }
02103 
02104     actual_msg_level = cpl_msg_get_level();
02105     cpl_msg_set_level(CPL_MSG_OFF);
02106     vec = kmo_dfs_load_vector(frameset, TELLURIC, *ifu_nr_telluric,is_noise);
02107     cpl_msg_set_level(actual_msg_level);
02108 
02109     if (cpl_error_get_code() != CPL_ERROR_NONE) cpl_error_reset();
02110 
02111     cpl_propertylist_delete(header); 
02112     if ((vec == NULL) && !is_noise && (no_subtract != -1)) {
02113         if (!no_subtract) {
02114             cpl_msg_warning(__func__, "No telluric on this detector");
02115         } else {
02116             cpl_msg_warning(__func__, "No telluric on this detector for IFU %d",
02117                     ifu_nr);
02118         }
02119     }
02120 
02121     return vec;
02122 }
02123