KMOS Pipeline Reference Manual  1.1.2
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.45 2013/05/07 08:39:13 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/05/07 08:39:13 $
00024  * $Revision: 1.45 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "kmo_utils.h"
00042 #include "kmo_functions.h"
00043 #include "kmo_priv_reconstruct.h"
00044 #include "kmo_priv_functions.h"
00045 #include "kmo_priv_lcorr.h"
00046 #include "kmo_cpl_extensions.h"
00047 #include "kmo_dfs.h"
00048 #include "kmo_error.h"
00049 #include "kmo_utils.h"
00050 #include "kmo_constants.h"
00051 #include "kmo_debug.h"
00052 
00053 /*-----------------------------------------------------------------------------
00054  *                          Functions prototypes
00055  *----------------------------------------------------------------------------*/
00056 
00057 static int kmo_reconstruct_create(cpl_plugin *);
00058 static int kmo_reconstruct_exec(cpl_plugin *);
00059 static int kmo_reconstruct_destroy(cpl_plugin *);
00060 static int kmo_reconstruct(cpl_parameterlist *, cpl_frameset *);
00061 
00062 /*-----------------------------------------------------------------------------
00063  *                          Static variables
00064  *----------------------------------------------------------------------------*/
00065 
00066 static char kmo_reconstruct_description[] =
00067 "Data with or without noise is reconstructed into a cube using the calibration\n"
00068 "frames XCAL, YCAL and LCAL. XCAL and YCAL are generated using recipe kmo_flat,\n"
00069 "LCAL is generated using recipe kmo_wave_cal.\n"
00070 "The input data can contain noise extensions and will be reconstructed into\n"
00071 "additional extensions.\n"
00072 "If an OH spectrum is given in the SOF file the lambda axis will be corrected\n"
00073 "using the OH lines as reference.\n"
00074 "\n"
00075 "BASIC PARAMETERS:\n"
00076 "-----------------\n"
00077 "--imethod\n"
00078 "The interpolation method used for reconstruction.\n"
00079 "\n"
00080 "--detimg\n"
00081 "Specify if the resampled image of the input frame should be generated. There-\n"
00082 "fore all slitlets of all IFUs are aligned one next to the other. This frame\n"
00083 "serves for quality control. One can immediately see if the reconstruction was\n"
00084 "successful.\n"
00085 "\n"
00086 "--file_extension"
00087 "Set this parameter to TRUE if the EXPTIME keyword should be appended to\n"
00088 "the output filenames.\n"
00089 "\n"
00090 "ADVANCED PARAMETERS\n"
00091 "-------------------\n"
00092 "--flux\n"
00093 "Specify if flux conservation should be applied.\n"
00094 "\n"
00095 "--neighborhoodRange\n"
00096 "Defines the range to search for neighbors during reconstruction\n"
00097 "\n"
00098 "--b_samples\n"
00099 "The number of samples in spectral direction for the reconstructed cube. Ideal-\n"
00100 "ly this number should be greater than 2048, the detector size.\n"
00101 "\n"
00102 "--b_start\n"
00103 "--b_end\n"
00104 "Used to define manually the start and end wavelength for the reconstructed\n"
00105 "cube. By default the internally defined values are used.\n"
00106 "\n"
00107 "--file_extension"
00108 "Set to TRUE if OBS_ID (from input frame header) should be appended to the\n"
00109 "output frame.\n"
00110 "\n"
00111 "--pix_scale"
00112 "Change the pixel scale [arcsec]. Default of 0.2\" results into cubes of\n"
00113 "14x14pix, a scale of 0.1\" results into cubes of 28x28pix, etc.\n"
00114 "\n"
00115 "-------------------------------------------------------------------------------\n"
00116 "  Input files:\n"
00117 "\n"
00118 "   DO                  KMOS                                                    \n"
00119 "   category            Type     Explanation                    Required #Frames\n"
00120 "   --------            -----    -----------                    -------- -------\n"
00121 "   DARK    or          RAW/F2D  data with                          Y       1   \n"
00122 "   FLAT_ON or          RAW/F2D  or without noise                               \n"
00123 "   ARC_ON  or          RAW/F2D                                                 \n"
00124 "   OBJECT  or          RAW                                                     \n"
00125 "   STD     or          RAW                                                     \n"
00126 "   SCIENCE             RAW                                                     \n"
00127 "   XCAL                F2D      x-direction calib. frame           Y       1   \n"
00128 "   YCAL                F2D      y-direction calib. frame           Y       1   \n"
00129 "   LCAL                F2D      Wavelength calib. frame            Y       1   \n"
00130 "   WAVE_BAND           F2L      Table with start-/end-wavelengths  Y       1   \n"
00131 "   OH_SPEC             F1S      Vector holding OH lines            N       1   \n"
00132 "\n"
00133 "  Output files:\n"
00134 "\n"
00135 "   DO                    KMOS\n"
00136 "   category              Type     Explanation\n"
00137 "   --------              -----    -----------\n"
00138 "   CUBE_DARK   or        F3I      Reconstructed cube   \n"
00139 "   CUBE_FLAT   or        RAW/F2D  with or without noise\n"
00140 "   CUBE_ARC    or                                      \n"
00141 "   CUBE_OBJECT or                                      \n"
00142 "   CUBE_STD    or                                      \n"
00143 "   CUBE_SCIENCE                                        \n"
00144 "-------------------------------------------------------------------------------\n"
00145 "\n";
00146 
00147 /*-----------------------------------------------------------------------------
00148  *                              Functions code
00149  *----------------------------------------------------------------------------*/
00150 
00167 int cpl_plugin_get_info(cpl_pluginlist *list)
00168 {
00169     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00170     cpl_plugin *plugin = &recipe->interface;
00171 
00172     cpl_plugin_init(plugin,
00173                         CPL_PLUGIN_API,
00174                         KMOS_BINARY_VERSION,
00175                         CPL_PLUGIN_TYPE_RECIPE,
00176                         "kmo_reconstruct",
00177                         "Performs the cube reconstruction "
00178                         "using different interpolation methods.",
00179                         kmo_reconstruct_description,
00180                         "Alex Agudo Berbel",
00181                         "agudo@mpe.mpg.de",
00182                         kmos_get_license(),
00183                         kmo_reconstruct_create,
00184                         kmo_reconstruct_exec,
00185                         kmo_reconstruct_destroy);
00186 
00187     cpl_pluginlist_append(list, plugin);
00188 
00189     return 0;
00190 }
00191 
00199 static int kmo_reconstruct_create(cpl_plugin *plugin)
00200 {
00201     cpl_recipe *recipe;
00202     cpl_parameter *p;
00203 
00204     /* Check that the plugin is part of a valid recipe */
00205     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00206         recipe = (cpl_recipe *)plugin;
00207     else
00208         return -1;
00209 
00210     /* Create the parameters list in the cpl_recipe object */
00211     recipe->parameters = cpl_parameterlist_new();
00212 
00213     /* Fill the parameters list */
00214     /* --imethod */
00215     p = cpl_parameter_new_value("kmos.kmo_reconstruct.imethod",
00216                                 CPL_TYPE_STRING,
00217                                 "Method to use for interpolation. "
00218                                 "[\"NN\" (nearest neighbour), "
00219                                 "\"lwNN\" (linear weighted nearest neighbor), "
00220                                 "\"swNN\" (square weighted nearest neighbor), "
00221                                 "\"MS\" (Modified Shepard's method)"
00222                                 "\"CS\" (Cubic spline)]",
00223                                 "kmos.kmo_reconstruct",
00224                                 "CS");
00225     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00226     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00227     cpl_parameterlist_append(recipe->parameters, p);
00228 
00229     /* --neighborhoodRange */
00230     p = cpl_parameter_new_value("kmos.kmo_reconstruct.neighborhoodRange",
00231                                 CPL_TYPE_DOUBLE,
00232                                 "Defines the range to search for neighbors. "
00233                                 "in pixels",
00234                                 "kmos.kmo_reconstruct",
00235                                 1.001);
00236     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00237     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00238     cpl_parameterlist_append(recipe->parameters, p);
00239 
00240     /* --flux */
00241     p = cpl_parameter_new_value("kmos.kmo_reconstruct.flux",
00242                                 CPL_TYPE_BOOL,
00243                                 "TRUE: Apply flux conservation. FALSE: otherwise",
00244                                 "kmos.kmo_reconstruct",
00245                                 FALSE);
00246     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00247     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00248     cpl_parameterlist_append(recipe->parameters, p);
00249 
00250     /* --detectorimage */
00251     p = cpl_parameter_new_value("kmos.kmo_reconstruct.detectorimage",
00252                                 CPL_TYPE_BOOL,
00253                                 "TRUE: if resampled detector frame should be "
00254                                 "created, FALSE: otherwise",
00255                                 "kmos.kmo_reconstruct",
00256                                 FALSE);
00257     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detimg");
00258     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00259     cpl_parameterlist_append(recipe->parameters, p);
00260 
00261     /* --file_extension */
00262     p = cpl_parameter_new_value("kmos.kmo_reconstruct.file_extension",
00263                                 CPL_TYPE_BOOL,
00264                                 "TRUE: if OBS_ID keyword should be appended to "
00265                                 "output frames, FALSE: otherwise",
00266                                 "kmos.kmo_reconstruct",
00267                                 FALSE);
00268     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "file_extension");
00269     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00270     cpl_parameterlist_append(recipe->parameters, p);
00271 
00272     /* --pix_scale */
00273     p = cpl_parameter_new_value("kmos.kmo_reconstruct.pix_scale",
00274                                 CPL_TYPE_DOUBLE,
00275                                 "Change the pixel scale [arcsec]. "
00276                                 "Default of 0.2\" results into cubes of 14x14pix, "
00277                                 "a scale of 0.1\" results into cubes of 28x28pix, "
00278                                 "etc.",
00279                                 "kmos.kmo_reconstruct",
00280                                 KMOS_PIX_RESOLUTION);
00281     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
00282     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00283     cpl_parameterlist_append(recipe->parameters, p);
00284 
00285     /* --dev_flip */
00286     p = cpl_parameter_new_value("kmos.kmo_reconstruct.dev_flip",
00287                                 CPL_TYPE_BOOL,
00288                                 "INTENDED FOR PIPELINE DEVELOPERS ONLY: "
00289                                 "Set this parameter to TRUE if the wavelengths "
00290                                 "are ascending on the detector from bottom to "
00291                                 "top (only for old simulation data).",
00292                                 "kmos.kmo_reconstruct",
00293                                 FALSE);
00294     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_flip");
00295     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00296     cpl_parameterlist_append(recipe->parameters, p);
00297 
00298     // add parameters for band-definition
00299     kmo_band_pars_create(recipe->parameters,
00300                          "kmos.kmo_reconstruct");
00301 
00302     return 0;
00303 }
00304 
00310 static int kmo_reconstruct_exec(cpl_plugin *plugin)
00311 {
00312     cpl_recipe  *recipe;
00313 
00314     /* Get the recipe out of the plugin */
00315     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00316         recipe = (cpl_recipe *)plugin;
00317     else return -1;
00318 
00319     return kmo_reconstruct(recipe->parameters, recipe->frames);
00320 }
00321 
00327 static int kmo_reconstruct_destroy(cpl_plugin *plugin)
00328 {
00329     cpl_recipe *recipe;
00330 
00331     /* Get the recipe out of the plugin */
00332     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00333         recipe = (cpl_recipe *)plugin;
00334     else return -1 ;
00335 
00336     cpl_parameterlist_delete(recipe->parameters);
00337     return 0 ;
00338 }
00339 
00354 static int kmo_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00355 {
00356     int                 ret_val                 = 0,
00357                         nr_devices              = 0,
00358                         i                       = 0,
00359                         j                       = 0,
00360                         flux                    = FALSE,
00361                         background              = FALSE,
00362                         index                   = 0,
00363                         detectorimage           = 0,
00364                         *bounds                 = NULL,
00365                         ifu_nr                  = 0,
00366                         obs_id                  = 0,
00367                         file_extension          = FALSE,
00368                         dev_flip                = FALSE,
00369                         detImgCube              = FALSE;
00370     float               *pdet_img_data          = NULL,
00371                         *pdet_img_noise         = NULL,
00372                         *slice                  = NULL;
00373     double              neighborhoodRange       = 1.001,
00374                         pix_scale               = 0.0;
00375 
00376     const char          *imethod                = NULL,
00377                         *input_frame_name       = NULL,
00378                         *output_frame_name      = NULL,
00379                         *filter_id              = NULL,
00380                         *filter_id_tmp          = NULL;
00381     char                *keyword                = NULL,
00382                         *filename_cube          = NULL,
00383                         *filename_img           = NULL,
00384 //                        *fn_lut                 = NULL,
00385                         *suffix                 = NULL,
00386                         *obs_suffix             = NULL,
00387                         *my_filter_id           = NULL,
00388                         *extname                = NULL;
00389     cpl_image           *lcal                   = NULL,
00390                         *det_img_data[KMOS_NR_DETECTORS],
00391                         *det_img_noise[KMOS_NR_DETECTORS],
00392                         *tmp_img                = NULL;
00393     cpl_imagelist       *cube_data              = NULL,
00394                         *cube_noise             = NULL;
00395     cpl_frame           *rec_frame              = NULL,
00396                         *xcal_frame             = NULL,
00397                         *ycal_frame             = NULL,
00398                         *lcal_frame             = NULL,
00399                         *ref_spectrum_frame     = NULL;
00400     cpl_propertylist    *main_header           = NULL,
00401                         *sub_header            = NULL,
00402                         *sub_header_orig       = NULL,
00403                         *actual_sub_header     = NULL,
00404                         *tmp_header            = NULL;
00405     cpl_table           *band_table            = NULL;
00406     gridDefinition      gd;
00407     main_fits_desc      desc1,
00408                         desc2;
00409     cpl_bivector        *obj_spectrum = NULL,
00410                         *ref_spectrum = NULL;
00411     cpl_vector          *peaks = NULL,
00412                         *range = NULL;
00413     cpl_polynomial      *lcorr_coeffs = NULL;
00414 
00415     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
00416         det_img_data[i] = NULL;
00417         det_img_noise[i] = NULL;
00418     }
00419 
00420     KMO_TRY
00421     {
00422         kmo_init_fits_desc(&desc1);
00423         kmo_init_fits_desc(&desc2);
00424 
00425         // --- check input ---
00426         KMO_TRY_ASSURE((parlist != NULL) &&
00427                        (frameset != NULL),
00428                        CPL_ERROR_NULL_INPUT,
00429                        "Not all input data is provided!");
00430 
00431         KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00432                        (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) ||
00433                        (cpl_frameset_count_tags(frameset, ARC_ON) == 1) ||
00434                        (cpl_frameset_count_tags(frameset, OBJECT) == 1) ||
00435                        (cpl_frameset_count_tags(frameset, STD) == 1) ||
00436                        (cpl_frameset_count_tags(frameset, SCIENCE) == 1),
00437                        CPL_ERROR_NULL_INPUT,
00438                        "A data frame (DARK, FLAT_ON, ARC_ON, OBJECT, STD or SCIENCE) must "
00439                        "be provided!");
00440 
00441         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00442                        CPL_ERROR_FILE_NOT_FOUND,
00443                        "XCAL frame missing in frameset!!");
00444 
00445         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00446                        CPL_ERROR_FILE_NOT_FOUND,
00447                        "YCAL frame missing in frameset!!");
00448 
00449         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00450                        CPL_ERROR_FILE_NOT_FOUND,
00451                        "LCAL frame missing in frameset!!");
00452 
00453         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00454                        CPL_ERROR_FILE_NOT_FOUND,
00455                        "WAVE_BAND frame missing in frameset!!");
00456 
00457         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_reconstruct") == 1,
00458                        CPL_ERROR_ILLEGAL_INPUT,
00459                        "Cannot identify RAW and CALIB frames!");
00460 
00461         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, OH_SPEC) == 0 ||
00462                        cpl_frameset_count_tags(frameset, OH_SPEC) == 1,
00463                        CPL_ERROR_ILLEGAL_INPUT,
00464                        "Only a single reference spectrum can be provided!");
00465 
00466         // --- get parameters ---
00467         cpl_msg_info("", "--- Parameter setup for kmo_reconstruct ---");
00468 
00469         KMO_TRY_EXIT_IF_NULL(
00470             imethod = kmo_dfs_get_parameter_string(parlist,
00471                                               "kmos.kmo_reconstruct.imethod"));
00472 
00473         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00474                        (strcmp(imethod, "lwNN") == 0) ||
00475                        (strcmp(imethod, "swNN") == 0) ||
00476                        (strcmp(imethod, "MS") == 0) ||
00477                        (strcmp(imethod, "CS") == 0),
00478                        CPL_ERROR_ILLEGAL_INPUT,
00479                        "imethod must be either \"NN\", \"lwNN\", "
00480                        "\"swNN\", \"MS\" or \"CS\"!");
00481 
00482         KMO_TRY_EXIT_IF_ERROR(
00483             kmo_dfs_print_parameter_help(parlist,
00484                                         "kmos.kmo_reconstruct.imethod"));
00485 
00486         flux = kmo_dfs_get_parameter_bool(parlist,
00487                                           "kmos.kmo_reconstruct.flux");
00488 
00489         KMO_TRY_ASSURE((flux == 0) ||
00490                        (flux == 1),
00491                        CPL_ERROR_ILLEGAL_INPUT,
00492                        "flux must be either FALSE or TRUE!");
00493 
00494         KMO_TRY_EXIT_IF_ERROR(
00495             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.flux"));
00496 
00497         detectorimage = kmo_dfs_get_parameter_bool(parlist,
00498                                           "kmos.kmo_reconstruct.detectorimage");
00499 
00500         KMO_TRY_ASSURE((detectorimage == 0) ||
00501                        (detectorimage == 1),
00502                        CPL_ERROR_ILLEGAL_INPUT,
00503                        "detectorimage must be either 0 or 1 !");
00504 
00505         KMO_TRY_EXIT_IF_ERROR(
00506             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.detectorimage"));
00507 
00508         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00509                 "kmos.kmo_reconstruct.neighborhoodRange");
00510         KMO_TRY_CHECK_ERROR_STATE();
00511         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00512                 CPL_ERROR_ILLEGAL_INPUT,
00513                 "neighborhoodRange must be greater than 0.0");
00514         KMO_TRY_EXIT_IF_ERROR(
00515             kmo_dfs_print_parameter_help(parlist,
00516                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00517 
00518         kmo_band_pars_load(parlist, "kmos.kmo_reconstruct");
00519 
00520         file_extension = kmo_dfs_get_parameter_bool(parlist,
00521                                         "kmos.kmo_reconstruct.file_extension");
00522         KMO_TRY_CHECK_ERROR_STATE();
00523         KMO_TRY_EXIT_IF_ERROR(
00524            kmo_dfs_print_parameter_help(parlist,
00525                                        "kmos.kmo_reconstruct.file_extension"));
00526 
00527         pix_scale = kmo_dfs_get_parameter_double(parlist,
00528                                         "kmos.kmo_reconstruct.pix_scale");
00529         KMO_TRY_CHECK_ERROR_STATE();
00530         KMO_TRY_EXIT_IF_ERROR(
00531            kmo_dfs_print_parameter_help(parlist,
00532                                        "kmos.kmo_reconstruct.pix_scale"));
00533         KMO_TRY_ASSURE((pix_scale >= 0.01) &&
00534                        (pix_scale <= 0.4),
00535                        CPL_ERROR_ILLEGAL_INPUT,
00536                        "pix_scale must be between 0.01 and 0.4 (results in cubes "
00537                        "with 7x7 to 280x280 pixels)!");
00538 
00539         dev_flip = kmo_dfs_get_parameter_bool(parlist,
00540                                            "kmos.kmo_reconstruct.dev_flip");
00541         KMO_TRY_CHECK_ERROR_STATE();
00542         KMO_TRY_EXIT_IF_ERROR(
00543             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.dev_flip"));
00544         KMO_TRY_ASSURE((dev_flip == TRUE) ||
00545                        (dev_flip == FALSE),
00546                        CPL_ERROR_ILLEGAL_INPUT,
00547                        "dev_flip must be TRUE or FALSE!");
00548 
00549 
00550         cpl_msg_info("", "-------------------------------------------");
00551 
00552         // load descriptor and header of data frame to reconstruct
00553         if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00554             input_frame_name = DARK;
00555             output_frame_name = CUBE_DARK;
00556         } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
00557             input_frame_name = FLAT_ON;
00558             output_frame_name = CUBE_FLAT;
00559         } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
00560             input_frame_name = ARC_ON;
00561             output_frame_name = CUBE_ARC;
00562         } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
00563             input_frame_name = OBJECT;
00564             output_frame_name = CUBE_OBJECT;
00565         } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
00566             input_frame_name = STD;
00567             output_frame_name = CUBE_STD;
00568         } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
00569             input_frame_name = SCIENCE;
00570             output_frame_name = CUBE_SCIENCE;
00571         }
00572 
00573         // assure that filters, grating and rotation offsets match for
00574         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
00575         // frames)
00576         // check if filter_id and grating_id match for all detectors
00577         KMO_TRY_EXIT_IF_ERROR(
00578             kmo_check_frame_setup(frameset, XCAL, YCAL,
00579                                        TRUE, FALSE, TRUE));
00580         KMO_TRY_EXIT_IF_ERROR(
00581             kmo_check_frame_setup(frameset, XCAL, LCAL,
00582                                        TRUE, FALSE, TRUE));
00583 
00584 // This check doesn't make sense here since OCS.ROT.NAANGLE is compared.
00585 // When creating the calibration files the RAW exposures needn't have been
00586 // provided in the same order
00587 //        KMO_TRY_EXIT_IF_ERROR(
00588 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00589 //        KMO_TRY_EXIT_IF_ERROR(
00590 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00591 
00592         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00593 
00594             // check if filters, gratings and rotator offset match
00595             // (except for DARK frames)
00596             KMO_TRY_EXIT_IF_ERROR(
00597                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00598                                            TRUE, FALSE, FALSE));
00599 /*
00600             // check if rotator offset don't differ to much
00601             cpl_frame        *f1 = NULL, *f2 = NULL;
00602             cpl_propertylist *h1 = NULL, *h2 = NULL;
00603             char             *kw = NULL;
00604             double           tmp_dbl1 = 0.0, tmp_dbl2 = 0.0;
00605 
00606             KMO_TRY_EXIT_IF_NULL(
00607                 f1 = kmo_dfs_get_frame(frameset, XCAL));
00608 
00609             KMO_TRY_EXIT_IF_NULL(
00610                 f2 = kmo_dfs_get_frame(frameset, input_frame_name));
00611             h1 = kmclipm_propertylist_load(cpl_frame_get_filename(f1), 0);
00612             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00613                 cpl_msg_error("","File not found: %s!",
00614                               cpl_frame_get_filename(f1));
00615                 KMO_TRY_CHECK_ERROR_STATE();
00616             }
00617 
00618             h2 = kmclipm_propertylist_load(cpl_frame_get_filename(f2), 0);
00619             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00620                 cpl_msg_error("","File not found: %s!",
00621                               cpl_frame_get_filename(f2));
00622                 KMO_TRY_CHECK_ERROR_STATE();
00623             }
00624             KMO_TRY_EXIT_IF_NULL(
00625                 kw = cpl_sprintf("%s", ROTANGLE));
00626             tmp_dbl1 = cpl_propertylist_get_double(h1, kw);
00627             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00628                 KMO_TRY_ASSURE(1 == 0,
00629                                CPL_ERROR_ILLEGAL_INPUT,
00630                                "keyword \n%s\n of frame %s is missing!",
00631                                keyword, XCAL);
00632             }
00633 
00634             tmp_dbl2 = cpl_propertylist_get_double(h2, kw);
00635             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00636                 KMO_TRY_ASSURE(1 == 0,
00637                                CPL_ERROR_ILLEGAL_INPUT,
00638                                "keyword \n%s\n of frame %s is missing!",
00639                                keyword, input_frame_name);
00640             }
00641 
00642             // strip angles below 0 deg and above 360 deg
00643             kmclipm_strip_angle(&tmp_dbl1);
00644             kmclipm_strip_angle(&tmp_dbl2);
00645 
00646             if (fabs(tmp_dbl1 - tmp_dbl2) > 30.) {
00647                 if ((fabs(tmp_dbl1) < 0.001) && (tmp_dbl2>330) && (tmp_dbl2<360)) {
00648                     // singularity!
00649                     // we have rot=0 for XCAL and rot>330 | rot<360 for input frame
00650                 } else {
00651                 cpl_msg_warning("","The angle of the calibration files (%g deg) "
00652                                 "and the angle of the frame to reconstruct"
00653                                 " (%g deg) differ by %g deg! Think about using "
00654                                 "calibration files matching better the actual "
00655                                 "rotator offset (ESO OCS ROT NAANGLE)",
00656                                 tmp_dbl1, tmp_dbl2,
00657                                 fabs(tmp_dbl1 - tmp_dbl2));
00658                 }
00659             }
00660 
00661             cpl_propertylist_delete(h1); h1 = NULL;
00662             cpl_propertylist_delete(h2); h2 = NULL;
00663             cpl_free(kw); kw = NULL;
00664 */
00665         }
00666 
00667         if (cpl_frameset_count_tags(frameset, OH_SPEC) != 0) {
00668             KMO_TRY_EXIT_IF_NULL(
00669                     ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC));
00670         }
00671 
00672         KMO_TRY_EXIT_IF_NULL(
00673             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00674         KMO_TRY_EXIT_IF_NULL(
00675             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00676         KMO_TRY_EXIT_IF_NULL(
00677             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00678 
00679         KMO_TRY_EXIT_IF_ERROR(
00680             kmo_check_frame_setup_md5_xycal(frameset));
00681         KMO_TRY_EXIT_IF_ERROR(
00682             kmo_check_frame_setup_md5(frameset));
00683 
00684         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00685         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00686         cpl_msg_info("", "-------------------------------------------");
00687 
00688 
00689         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00690         KMO_TRY_CHECK_ERROR_STATE();
00691 
00692         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00693                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00694                        (desc1.ex_badpix == FALSE) &&
00695                        ((desc1.fits_type == raw_fits) ||
00696                         (desc1.fits_type == f2d_fits)) &&
00697                        (desc1.frame_type == detector_frame),
00698                        CPL_ERROR_ILLEGAL_INPUT,
00699                        "The frame to reconstruct isn't in the correct format!!!"
00700                        "Exactly 3 frames, or 6 with noise are expected!");
00701 
00702         if (!desc1.ex_noise) {
00703             nr_devices = desc1.nr_ext;
00704         } else {
00705             nr_devices = desc1.nr_ext / 2;
00706         }
00707 
00708         // compare descriptor of XCAL and data frame to reconstruct
00709         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00710         KMO_TRY_CHECK_ERROR_STATE();
00711 
00712         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00713                        (desc1.ex_badpix == desc2.ex_badpix) &&
00714                        (desc1.frame_type == desc2.frame_type),
00715                        CPL_ERROR_ILLEGAL_INPUT,
00716                        "XCAL isn't in the correct format!!!");
00717 
00718         kmo_free_fits_desc(&desc2);
00719 
00720         // compare descriptor of YCAL and data frame to reconstruct
00721         kmo_init_fits_desc(&desc2);
00722 
00723         KMO_TRY_EXIT_IF_NULL(
00724             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00725 
00726         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
00727         KMO_TRY_CHECK_ERROR_STATE();
00728 
00729         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00730                        (desc1.ex_badpix == desc2.ex_badpix) &&
00731                        (desc1.frame_type == desc2.frame_type),
00732                        CPL_ERROR_ILLEGAL_INPUT,
00733                        "YCAL isn't in the correct format!!!");
00734 
00735         kmo_free_fits_desc(&desc2);
00736 
00737         // compare descriptor of LCAL and data frame to reconstruct
00738         kmo_init_fits_desc(&desc2);
00739 
00740         KMO_TRY_EXIT_IF_NULL(
00741             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00742 
00743         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
00744         KMO_TRY_CHECK_ERROR_STATE();
00745 
00746         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00747                        (desc1.ex_badpix == desc2.ex_badpix) &&
00748                        (desc1.frame_type == desc2.frame_type),
00749                        CPL_ERROR_ILLEGAL_INPUT,
00750                        "LCAL isn't in the correct format!!!");
00751 
00752         kmo_free_fits_desc(&desc2);
00753 
00754         //
00755         // --- load, update & save primary header ---
00756         //
00757         KMO_TRY_EXIT_IF_NULL(
00758             main_header = kmo_dfs_load_primary_header(frameset,
00759                                                       input_frame_name));
00760 
00761         KMO_TRY_EXIT_IF_NULL(
00762             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00763 
00764         // assert that filters have correct IDs and that all detectors of all
00765         // input frames have the same filter set
00766         for (i = 1; i <= nr_devices; i++) {
00767             // ESO INS FILTi ID
00768             KMO_TRY_EXIT_IF_NULL(
00769                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00770                                       IFU_FILTID_POSTFIX));
00771 
00772             KMO_TRY_EXIT_IF_NULL(
00773                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00774 
00775             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00776                            (strcmp(filter_id, "YJ") == 0) ||
00777                            (strcmp(filter_id, "H") == 0) ||
00778                            (strcmp(filter_id, "K") == 0) ||
00779                            (strcmp(filter_id, "HK") == 0),
00780                            CPL_ERROR_ILLEGAL_INPUT,
00781                            "Filter ID in primary header of LCAL frame must "
00782                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00783                            "\"HK\" !");
00784 
00785             if (strcmp(input_frame_name, DARK) != 0) {
00786                 // dark needn't to be taken with filter!
00787 
00788                 KMO_TRY_EXIT_IF_NULL(
00789                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00790                                                                 keyword));
00791                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00792                                CPL_ERROR_ILLEGAL_INPUT,
00793                                "Filter IDs must be the same for LCAL frame and "
00794                                "the frame to reconstruct!"
00795                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00796                                i, filter_id, input_frame_name, filter_id_tmp);
00797             }
00798             cpl_free(keyword); keyword = NULL;
00799         }
00800         KMO_TRY_EXIT_IF_NULL(
00801             my_filter_id = cpl_strdup(filter_id));
00802         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00803 
00804         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00805         KMO_TRY_CHECK_ERROR_STATE();
00806 
00807         KMO_TRY_EXIT_IF_NULL(
00808             filename_cube = cpl_sprintf("%s", output_frame_name));
00809         KMO_TRY_EXIT_IF_NULL(
00810             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00811         if (file_extension) {
00812             KMO_TRY_EXIT_IF_NULL(
00813                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00814         } else {
00815             KMO_TRY_EXIT_IF_NULL(
00816                 obs_suffix = cpl_sprintf("%s", ""));
00817         }
00818 
00819         KMO_TRY_EXIT_IF_ERROR(
00820             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00821                                      rec_frame, NULL, parlist, cpl_func));
00822 
00823         // setup grid definition, wavelength start and end points will be set
00824         // in the detector loop
00825         KMO_TRY_EXIT_IF_ERROR(
00826             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale));
00827 
00828         KMO_TRY_EXIT_IF_NULL(
00829             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00830 
00831         KMO_TRY_EXIT_IF_NULL(
00832             bounds = kmclipm_extract_bounds(tmp_header));
00833         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00834 
00835         if (detectorimage == TRUE) {
00836             KMO_TRY_EXIT_IF_ERROR(
00837                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00838                                          rec_frame, NULL, parlist, cpl_func));
00839         }
00840 
00841         /* loop through all detectors */
00842         for (i = 1; i <= nr_devices; i++) {
00843             cpl_msg_info("","Processing detector No. %d", i);
00844 
00845             // load lcal
00846             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00847             // doesn't differ too much with different ROTANGLEs.
00848             double rotangle_found;
00849             KMO_TRY_EXIT_IF_NULL(
00850                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00851                                               FALSE, NULL, &rotangle_found));
00852 
00853             char *tmp_band_method = getenv("KMO_BAND_METHOD");
00854             int band_method = 0;
00855             if (tmp_band_method != NULL) {
00856                 band_method = atoi(tmp_band_method);
00857             }
00858 
00859             KMO_TRY_EXIT_IF_NULL(
00860                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00861 
00862             KMO_TRY_EXIT_IF_ERROR(
00863                 kmclipm_setup_grid_band_lcal(&gd, lcal, my_filter_id,
00864                                              band_method, band_table));
00865             cpl_table_delete(band_table); band_table = NULL;
00866 
00867             cpl_image_delete(lcal); lcal = NULL;
00868 
00869             if (detectorimage == TRUE) {
00870                 KMO_TRY_EXIT_IF_NULL(
00871                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00872                                                       gd.l.dim, CPL_TYPE_FLOAT));
00873                 KMO_TRY_EXIT_IF_NULL(
00874                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00875 
00876                 KMO_TRY_EXIT_IF_NULL(
00877                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00878                                                       gd.l.dim, CPL_TYPE_FLOAT));
00879                 KMO_TRY_EXIT_IF_NULL(
00880                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00881             }
00882 
00883 
00884             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00885                 /* update sub-header */
00886                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00887 
00888                 /* load raw image and sub-header*/
00889                 KMO_TRY_EXIT_IF_NULL(
00890                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00891                                                          i, FALSE));
00892                 KMO_TRY_EXIT_IF_NULL(
00893                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00894 
00895                 // check if IFU is valid according to main header keywords &
00896                 // calibration files
00897 
00898                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00899                     KMO_TRY_EXIT_IF_NULL(
00900                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00901                                               IFU_VALID_POSTFIX));
00902                     KMO_TRY_CHECK_ERROR_STATE();
00903                     cpl_propertylist_get_string(main_header, keyword);
00904                     cpl_free(keyword); keyword = NULL;
00905                 } else {
00906                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00907                     // reconstructed
00908                     cpl_propertylist_get_string(main_header, "ggg");
00909                 }
00910 
00911                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00912                     (bounds[2*(ifu_nr-1)] != -1) &&
00913                     (bounds[2*(ifu_nr-1)+1] != -1))
00914                 {
00915                     cpl_error_reset();
00916                     // IFU is valid
00917                     actual_sub_header = sub_header;
00918 
00919                     // calculate WCS
00920                     KMO_TRY_EXIT_IF_ERROR(
00921                         kmo_calc_wcs_gd(main_header, actual_sub_header, ifu_nr, gd));
00922 
00923                     // reconstruct data and noise (if available)
00924                     if (j == 0) {
00925                         sat_mode_msg = FALSE;
00926                     } else {
00927                         sat_mode_msg = TRUE;
00928                     }
00929                     KMO_TRY_EXIT_IF_ERROR(
00930                         kmo_reconstruct_sci(ifu_nr,
00931                                             bounds[2*(ifu_nr-1)],
00932                                             bounds[2*(ifu_nr-1)+1],
00933                                             rec_frame,
00934                                             input_frame_name,
00935                                             NULL,
00936                                             NULL,
00937                                             NULL,
00938                                             xcal_frame,
00939                                             ycal_frame,
00940                                             lcal_frame,
00941                                             NULL,
00942                                             &gd,
00943                                             &cube_data,
00944                                             &cube_noise,
00945                                             flux,
00946                                             background));
00947 
00948                     if (ref_spectrum_frame != NULL) {
00949 
00950                         if (peaks == NULL) {
00951                             KMO_TRY_EXIT_IF_NULL(
00952                                     range = cpl_vector_new(2));
00953                             KMO_TRY_EXIT_IF_ERROR(
00954                                     cpl_vector_set(range, 0, gd.l.start));
00955                             KMO_TRY_EXIT_IF_ERROR(
00956                                     cpl_vector_set(range, 1, gd.l.start + gd.l.delta * gd.l.dim));
00957                              KMO_TRY_EXIT_IF_NULL(
00958                                     ref_spectrum = kmo_lcorr_read_reference_spectrum(
00959                                             cpl_frame_get_filename(ref_spectrum_frame),NULL));
00960                             KMO_TRY_EXIT_IF_NULL(
00961                                     peaks = kmo_lcorr_get_peak_lambdas(ref_spectrum, 0.2, range));
00962 
00963                             cpl_vector_delete(range);
00964                         }
00965 
00966                         KMO_TRY_EXIT_IF_ERROR(
00967                                 cpl_propertylist_set_int(actual_sub_header,NAXIS,3));
00968                         KMO_TRY_EXIT_IF_NULL(
00969                                 tmp_img = cpl_imagelist_get(cube_data, 0));
00970                         KMO_TRY_EXIT_IF_ERROR(
00971                                 cpl_propertylist_set_int(actual_sub_header,NAXIS1,
00972                                         cpl_image_get_size_x(tmp_img)));
00973                         KMO_TRY_EXIT_IF_ERROR(
00974                                 cpl_propertylist_set_int(actual_sub_header,NAXIS2,
00975                                         cpl_image_get_size_y(tmp_img)));
00976                         KMO_TRY_EXIT_IF_ERROR(
00977                                 cpl_propertylist_append_int(actual_sub_header,NAXIS3,
00978                                         cpl_imagelist_get_size(cube_data)));
00979                         KMO_TRY_EXIT_IF_NULL(
00980                                 obj_spectrum = kmo_lcorr_extract_spectrum(
00981                                         cube_data, actual_sub_header, 0.8, NULL));
00982 
00983 /*
00984  // enables additional debugging output
00985                         char *idlfilename = cpl_sprintf("idl_%2.2d.dat",ifu_nr);
00986                         kmo_lcorr_open_debug_file(idlfilename);
00987                         cpl_free(idlfilename);
00988 */
00989 
00990                         KMO_TRY_EXIT_IF_NULL(
00991                                 lcorr_coeffs = kmo_lcorr_crosscorrelate_spectra(
00992                                         obj_spectrum, ref_spectrum, peaks, 0.002));
00993 /*
00994  // debugging output is a single file for each IFU, so close it now
00995                          kmo_lcorr_close_debug_file();
00996 */
00997 
00998                         cpl_bivector_delete(obj_spectrum);
00999 
01000                         const int format_width = 14;
01001                         const int max_coeffs = 6;
01002                         char *coeff_string = NULL;
01003                         char coeff_dump[format_width * max_coeffs + 1];
01004                         cpl_size pows[1];
01005                         coeff_dump[0] = 0;
01006                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs) && ic < max_coeffs; ic++) {
01007                             pows[0] = ic;
01008                             coeff_string = cpl_sprintf(" %*g,",
01009                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs,pows));
01010                             strncat(coeff_dump, coeff_string, format_width);
01011                             cpl_free(coeff_string);
01012                         }
01013                         cpl_msg_debug("","Lambda correction coeffs for IFU %d %s",ifu_nr, coeff_dump);
01014 
01015                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01016                         cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01017                         KMO_TRY_EXIT_IF_ERROR(
01018                             kmo_reconstruct_sci(ifu_nr,
01019                                                 bounds[2*(ifu_nr-1)],
01020                                                 bounds[2*(ifu_nr-1)+1],
01021                                                 rec_frame,
01022                                                 input_frame_name,
01023                                                 NULL,
01024                                                 NULL,
01025                                                 NULL,
01026                                                 xcal_frame,
01027                                                 ycal_frame,
01028                                                 lcal_frame,
01029                                                 lcorr_coeffs,
01030                                                 &gd,
01031                                                 &cube_data,
01032                                                 &cube_noise,
01033                                                 flux,
01034                                                 background));
01035 /*
01036  // show that lambda correction improved the data cube, a second one would improve even more
01037 
01038                         cpl_bivector *obj_spectrum2, *obj_spectrum3;
01039                         cpl_polynomial *lcorr_coeffs2, *lcorr_coeffs3;
01040                         KMO_TRY_EXIT_IF_NULL(
01041                                 obj_spectrum2 = kmo_lcorr_extract_spectrum(
01042                                         cube_data, actual_sub_header, 0.8, NULL));
01043 
01044                         KMO_TRY_EXIT_IF_NULL(
01045                                 lcorr_coeffs2 = kmo_lcorr_crosscorrelate_spectra(
01046                                         obj_spectrum2, ref_spectrum, peaks, 0.002));
01047 
01048                         cpl_bivector_delete(obj_spectrum2);
01049 
01050                         coeff_dump[0] = 0;
01051                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs2) && ic < max_coeffs; ic++) {
01052                             pows[0] = ic;
01053                             coeff_string = cpl_sprintf(" %*g,",
01054                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs2,pows));
01055                             strncat(coeff_dump, coeff_string, format_width);
01056                             cpl_free(coeff_string);
01057                             double c1 =  cpl_polynomial_get_coeff(lcorr_coeffs,pows);
01058                             double c2 =  cpl_polynomial_get_coeff(lcorr_coeffs2,pows);
01059                             cpl_polynomial_set_coeff(lcorr_coeffs, pows, c1+c2);
01060                         }
01061                         cpl_msg_debug("","Lambda correction coeffs for ifu %d %s",ifu_nr, coeff_dump);
01062                         cpl_polynomial_delete(lcorr_coeffs2); lcorr_coeffs2=NULL;
01063 
01064                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01065                         cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01066                         KMO_TRY_EXIT_IF_ERROR(
01067                             kmo_reconstruct_sci(ifu_nr,
01068                                                 bounds[2*(ifu_nr-1)],
01069                                                 bounds[2*(ifu_nr-1)+1],
01070                                                 rec_frame,
01071                                                 input_frame_name,
01072                                                 NULL,
01073                                                 NULL,
01074                                                 NULL,
01075                                                 xcal_frame,
01076                                                 ycal_frame,
01077                                                 lcal_frame,
01078                                                 lcorr_coeffs,
01079                                                 &gd,
01080                                                 &cube_data,
01081                                                 &cube_noise,
01082                                                 flux,
01083                                                 background));
01084 
01085                         KMO_TRY_EXIT_IF_NULL(
01086                                 obj_spectrum3 = kmo_lcorr_extract_spectrum(
01087                                         cube_data, actual_sub_header, 0.8, NULL));
01088 
01089                         KMO_TRY_EXIT_IF_NULL(
01090                                 lcorr_coeffs3 = kmo_lcorr_crosscorrelate_spectra(
01091                                         obj_spectrum3, ref_spectrum, peaks, 0.002));
01092 
01093                         cpl_bivector_delete(obj_spectrum3);
01094 
01095                         coeff_dump[0] = 0;
01096                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs3) && ic < max_coeffs; ic++) {
01097                             pows[0] = ic;
01098                             coeff_string = cpl_sprintf(" %*g,",
01099                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs3,pows));
01100                             strncat(coeff_dump, coeff_string, format_width);
01101                             cpl_free(coeff_string);
01102                         }
01103                         cpl_msg_debug("","Lambda correction coeffs for iFu %d %s",ifu_nr, coeff_dump);
01104                         cpl_polynomial_delete(lcorr_coeffs3); lcorr_coeffs3=NULL;
01105 */
01106                         cpl_polynomial_delete(lcorr_coeffs);
01107 
01108                     }
01109                 } else {
01110                     // IFU is invalid
01111                     actual_sub_header = sub_header_orig;
01112                     cpl_error_reset();
01113                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
01114 
01115                 if (detectorimage) {
01116                     if (cube_data != NULL) {
01117                         for (int l=0; l<gd.l.dim; l++) {
01118                             KMO_TRY_EXIT_IF_NULL(
01119                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
01120                             for (int y=0; y<gd.y.dim; y++) {
01121                                 for (int x=0; x<gd.x.dim; x++) {
01122                                     int ix = x +
01123                                              y * gd.x.dim +
01124                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01125                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01126                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
01127                                 }
01128                             }
01129                         }
01130                     }
01131                     if (cube_noise != NULL) {
01132                         if (detectorimage) {
01133                             detImgCube = TRUE;
01134                         }
01135                         for (int l=0; l<gd.l.dim; l++) {
01136                             KMO_TRY_EXIT_IF_NULL(
01137                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
01138                             for (int y=0; y<gd.y.dim; y++) {
01139                                 for (int x=0; x<gd.x.dim; x++) {
01140                                     int ix = x +
01141                                              y * gd.x.dim +
01142                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01143                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01144                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
01145                                 }
01146                             }
01147                         }
01148                     }
01149                 }
01150 
01151                 // save output
01152                 KMO_TRY_EXIT_IF_NULL(
01153                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
01154                                                   EXT_DATA));
01155 
01156                 KMO_TRY_EXIT_IF_ERROR(
01157                     kmclipm_update_property_string(actual_sub_header,
01158                                             EXTNAME,
01159                                             extname,
01160                                             "FITS extension name"));
01161 
01162                 cpl_free(extname); extname = NULL;
01163 
01164                 KMO_TRY_EXIT_IF_ERROR(
01165                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
01166                                       actual_sub_header, 0./0.));
01167 
01168                 if (cube_noise != NULL) {
01169                     KMO_TRY_EXIT_IF_NULL(
01170                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01171                                                       EXT_NOISE));
01172 
01173                     KMO_TRY_EXIT_IF_ERROR(
01174                         kmclipm_update_property_string(actual_sub_header,
01175                                                 EXTNAME,
01176                                                 extname,
01177                                                 "FITS extension name"));
01178 
01179                     cpl_free(extname); extname = NULL;
01180 
01181                     KMO_TRY_EXIT_IF_ERROR(
01182                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
01183                                           actual_sub_header, 0./0.));
01184                 }
01185 
01186                 cpl_imagelist_delete(cube_data); cube_data = NULL;
01187                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01188                 cpl_propertylist_delete(sub_header); sub_header = NULL;
01189                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01190             } // for j IFUs
01191 
01192             if (detectorimage) {
01193                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01194                                            i, FALSE);
01195                 KMO_TRY_CHECK_ERROR_STATE();
01196 
01197                 KMO_TRY_EXIT_IF_NULL(
01198                     tmp_header = kmclipm_propertylist_load(
01199                                          cpl_frame_get_filename(rec_frame), index));
01200                 KMO_TRY_EXIT_IF_ERROR(
01201                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
01202                                          obs_suffix, tmp_header, dev_flip, FALSE));
01203                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01204 
01205                 if (detImgCube) {
01206                     if (desc1.ex_noise) {
01207                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01208                                                    i, TRUE);
01209                         KMO_TRY_CHECK_ERROR_STATE();
01210                     } else {
01211                         // use same index as for data frame, since input frame
01212                         // has just 3 extensions
01213                     }
01214                     KMO_TRY_EXIT_IF_NULL(
01215                         tmp_header = kmclipm_propertylist_load(
01216                                              cpl_frame_get_filename(rec_frame), index));
01217                     KMO_TRY_EXIT_IF_ERROR(
01218                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01219                                              obs_suffix, tmp_header, dev_flip, TRUE));
01220                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01221                 }
01222             }
01223 
01224             // free memory
01225             cpl_imagelist_delete(cube_data); cube_data = NULL;
01226             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01227             cpl_propertylist_delete(sub_header); sub_header = NULL;
01228             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01229         } // for i devices
01230     }
01231     KMO_CATCH
01232     {
01233         KMO_CATCH_MSG();
01234         ret_val = -1;
01235     }
01236 
01237     kmo_free_fits_desc(&desc1);
01238     kmo_free_fits_desc(&desc2);
01239     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
01240         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01241         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01242     }
01243     cpl_free(my_filter_id); my_filter_id = NULL;
01244     cpl_free(bounds); bounds = NULL;
01245     cpl_propertylist_delete(main_header); main_header = NULL;
01246     cpl_propertylist_delete(sub_header); sub_header = NULL;
01247     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01248     cpl_imagelist_delete(cube_data); cube_data = NULL;
01249     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01250     cpl_free(obs_suffix); obs_suffix = NULL;
01251     cpl_free(suffix); suffix = NULL;
01252     cpl_free(filename_img); filename_img = NULL;
01253     cpl_free(filename_cube); filename_cube = NULL;
01254     if (peaks != NULL ) {cpl_vector_delete(peaks);}
01255     if (ref_spectrum  != NULL ) {cpl_bivector_delete(ref_spectrum);}
01256     sat_mode_msg = FALSE;
01257 
01258     return ret_val;
01259 }
01260