KMOS Pipeline Reference Manual  1.1.3
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.46 2013/05/13 12:24:09 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/13 12:24:09 $
00024  * $Revision: 1.46 $
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                         if (peaks == NULL) {
00950                             KMO_TRY_EXIT_IF_NULL(
00951                                 range = cpl_vector_new(2));
00952                             KMO_TRY_EXIT_IF_ERROR(
00953                                 cpl_vector_set(range, 0, gd.l.start));
00954                             KMO_TRY_EXIT_IF_ERROR(
00955                                 cpl_vector_set(range, 1, gd.l.start + gd.l.delta * gd.l.dim));
00956                              KMO_TRY_EXIT_IF_NULL(
00957                                 ref_spectrum = kmo_lcorr_read_reference_spectrum(
00958                                                   cpl_frame_get_filename(ref_spectrum_frame),NULL));
00959                             KMO_TRY_EXIT_IF_NULL(
00960                                 peaks = kmo_lcorr_get_peak_lambdas(ref_spectrum, 0.2, range));
00961 
00962                             cpl_vector_delete(range);
00963                         }
00964 
00965                         KMO_TRY_EXIT_IF_ERROR(
00966                             cpl_propertylist_set_int(actual_sub_header,NAXIS,3));
00967                         KMO_TRY_EXIT_IF_NULL(
00968                             tmp_img = cpl_imagelist_get(cube_data, 0));
00969                         KMO_TRY_EXIT_IF_ERROR(
00970                             cpl_propertylist_set_int(actual_sub_header,NAXIS1,
00971                                                      cpl_image_get_size_x(tmp_img)));
00972                         KMO_TRY_EXIT_IF_ERROR(
00973                             cpl_propertylist_set_int(actual_sub_header,NAXIS2,
00974                                                      cpl_image_get_size_y(tmp_img)));
00975                         KMO_TRY_EXIT_IF_ERROR(
00976                             cpl_propertylist_append_int(actual_sub_header,NAXIS3,
00977                                                         cpl_imagelist_get_size(cube_data)));
00978                         KMO_TRY_EXIT_IF_NULL(
00979                             obj_spectrum = kmo_lcorr_extract_spectrum(
00980                                                     cube_data, actual_sub_header, 0.8, NULL));
00981 
00982 /*
00983  // enables additional debugging output
00984                         char *idlfilename = cpl_sprintf("idl_%2.2d.dat",ifu_nr);
00985                         kmo_lcorr_open_debug_file(idlfilename);
00986                         cpl_free(idlfilename);
00987 */
00988 
00989                         KMO_TRY_EXIT_IF_NULL(
00990                             lcorr_coeffs = kmo_lcorr_crosscorrelate_spectra(
00991                                                 obj_spectrum, ref_spectrum, peaks, 0.002));
00992 /*
00993  // debugging output is a single file for each IFU, so close it now
00994                          kmo_lcorr_close_debug_file();
00995 */
00996 
00997                         cpl_bivector_delete(obj_spectrum);
00998 
00999                         const int format_width = 14;
01000                         const int max_coeffs = 6;
01001                         char *coeff_string = NULL;
01002                         char coeff_dump[format_width * max_coeffs + 1];
01003                         cpl_size pows[1];
01004                         coeff_dump[0] = 0;
01005                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs) && ic < max_coeffs; ic++) {
01006                             pows[0] = ic;
01007                             coeff_string = cpl_sprintf(" %*g,",
01008                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs,pows));
01009                             strncat(coeff_dump, coeff_string, format_width);
01010                             cpl_free(coeff_string);
01011                         }
01012                         cpl_msg_debug("","Lambda correction coeffs for IFU %d %s",ifu_nr, coeff_dump);
01013 
01014                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01015                         cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01016                         KMO_TRY_EXIT_IF_ERROR(
01017                             kmo_reconstruct_sci(ifu_nr,
01018                                                 bounds[2*(ifu_nr-1)],
01019                                                 bounds[2*(ifu_nr-1)+1],
01020                                                 rec_frame,
01021                                                 input_frame_name,
01022                                                 NULL,
01023                                                 NULL,
01024                                                 NULL,
01025                                                 xcal_frame,
01026                                                 ycal_frame,
01027                                                 lcal_frame,
01028                                                 lcorr_coeffs,
01029                                                 &gd,
01030                                                 &cube_data,
01031                                                 &cube_noise,
01032                                                 flux,
01033                                                 background));
01034 /*
01035  // show that lambda correction improved the data cube, a second one would improve even more
01036 
01037                         cpl_bivector *obj_spectrum2, *obj_spectrum3;
01038                         cpl_polynomial *lcorr_coeffs2, *lcorr_coeffs3;
01039                         KMO_TRY_EXIT_IF_NULL(
01040                                 obj_spectrum2 = kmo_lcorr_extract_spectrum(
01041                                         cube_data, actual_sub_header, 0.8, NULL));
01042 
01043                         KMO_TRY_EXIT_IF_NULL(
01044                                 lcorr_coeffs2 = kmo_lcorr_crosscorrelate_spectra(
01045                                         obj_spectrum2, ref_spectrum, peaks, 0.002));
01046 
01047                         cpl_bivector_delete(obj_spectrum2);
01048 
01049                         coeff_dump[0] = 0;
01050                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs2) && ic < max_coeffs; ic++) {
01051                             pows[0] = ic;
01052                             coeff_string = cpl_sprintf(" %*g,",
01053                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs2,pows));
01054                             strncat(coeff_dump, coeff_string, format_width);
01055                             cpl_free(coeff_string);
01056                             double c1 =  cpl_polynomial_get_coeff(lcorr_coeffs,pows);
01057                             double c2 =  cpl_polynomial_get_coeff(lcorr_coeffs2,pows);
01058                             cpl_polynomial_set_coeff(lcorr_coeffs, pows, c1+c2);
01059                         }
01060                         cpl_msg_debug("","Lambda correction coeffs for ifu %d %s",ifu_nr, coeff_dump);
01061                         cpl_polynomial_delete(lcorr_coeffs2); lcorr_coeffs2=NULL;
01062 
01063                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01064                         cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01065                         KMO_TRY_EXIT_IF_ERROR(
01066                             kmo_reconstruct_sci(ifu_nr,
01067                                                 bounds[2*(ifu_nr-1)],
01068                                                 bounds[2*(ifu_nr-1)+1],
01069                                                 rec_frame,
01070                                                 input_frame_name,
01071                                                 NULL,
01072                                                 NULL,
01073                                                 NULL,
01074                                                 xcal_frame,
01075                                                 ycal_frame,
01076                                                 lcal_frame,
01077                                                 lcorr_coeffs,
01078                                                 &gd,
01079                                                 &cube_data,
01080                                                 &cube_noise,
01081                                                 flux,
01082                                                 background));
01083 
01084                         KMO_TRY_EXIT_IF_NULL(
01085                                 obj_spectrum3 = kmo_lcorr_extract_spectrum(
01086                                         cube_data, actual_sub_header, 0.8, NULL));
01087 
01088                         KMO_TRY_EXIT_IF_NULL(
01089                                 lcorr_coeffs3 = kmo_lcorr_crosscorrelate_spectra(
01090                                         obj_spectrum3, ref_spectrum, peaks, 0.002));
01091 
01092                         cpl_bivector_delete(obj_spectrum3);
01093 
01094                         coeff_dump[0] = 0;
01095                         for (int ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs3) && ic < max_coeffs; ic++) {
01096                             pows[0] = ic;
01097                             coeff_string = cpl_sprintf(" %*g,",
01098                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs3,pows));
01099                             strncat(coeff_dump, coeff_string, format_width);
01100                             cpl_free(coeff_string);
01101                         }
01102                         cpl_msg_debug("","Lambda correction coeffs for iFu %d %s",ifu_nr, coeff_dump);
01103                         cpl_polynomial_delete(lcorr_coeffs3); lcorr_coeffs3=NULL;
01104 */
01105                         cpl_polynomial_delete(lcorr_coeffs);
01106 
01107                     }
01108 
01109                     // scale flux according to pixel_scale
01110                     KMO_TRY_EXIT_IF_NULL(
01111                         tmp_img = cpl_imagelist_get(cube_data, 0));
01112                     double scaling = (cpl_image_get_size_x(tmp_img)*cpl_image_get_size_y(tmp_img)) /
01113                                      (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01114                     KMO_TRY_EXIT_IF_ERROR(
01115                         cpl_imagelist_divide_scalar(cube_data, scaling));
01116                     if (cube_noise != NULL) {
01117                         KMO_TRY_EXIT_IF_ERROR(
01118                             cpl_imagelist_divide_scalar(cube_noise, scaling));
01119                     }
01120                 } else {
01121                     // IFU is invalid
01122                     actual_sub_header = sub_header_orig;
01123                     cpl_error_reset();
01124                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
01125 
01126                 if (detectorimage) {
01127                     if (cube_data != NULL) {
01128                         for (int l=0; l<gd.l.dim; l++) {
01129                             KMO_TRY_EXIT_IF_NULL(
01130                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
01131                             for (int y=0; y<gd.y.dim; y++) {
01132                                 for (int x=0; x<gd.x.dim; x++) {
01133                                     int ix = x +
01134                                              y * gd.x.dim +
01135                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01136                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01137                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
01138                                 }
01139                             }
01140                         }
01141                     }
01142                     if (cube_noise != NULL) {
01143                         if (detectorimage) {
01144                             detImgCube = TRUE;
01145                         }
01146                         for (int l=0; l<gd.l.dim; l++) {
01147                             KMO_TRY_EXIT_IF_NULL(
01148                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
01149                             for (int y=0; y<gd.y.dim; y++) {
01150                                 for (int x=0; x<gd.x.dim; x++) {
01151                                     int ix = x +
01152                                              y * gd.x.dim +
01153                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01154                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01155                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
01156                                 }
01157                             }
01158                         }
01159                     }
01160                 }
01161 
01162                 // save output
01163                 KMO_TRY_EXIT_IF_NULL(
01164                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
01165                                                   EXT_DATA));
01166 
01167                 KMO_TRY_EXIT_IF_ERROR(
01168                     kmclipm_update_property_string(actual_sub_header,
01169                                             EXTNAME,
01170                                             extname,
01171                                             "FITS extension name"));
01172 
01173                 cpl_free(extname); extname = NULL;
01174 
01175                 KMO_TRY_EXIT_IF_ERROR(
01176                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
01177                                       actual_sub_header, 0./0.));
01178 
01179                 if (cube_noise != NULL) {
01180                     KMO_TRY_EXIT_IF_NULL(
01181                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01182                                                       EXT_NOISE));
01183 
01184                     KMO_TRY_EXIT_IF_ERROR(
01185                         kmclipm_update_property_string(actual_sub_header,
01186                                                 EXTNAME,
01187                                                 extname,
01188                                                 "FITS extension name"));
01189 
01190                     cpl_free(extname); extname = NULL;
01191 
01192                     KMO_TRY_EXIT_IF_ERROR(
01193                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
01194                                           actual_sub_header, 0./0.));
01195                 }
01196 
01197                 cpl_imagelist_delete(cube_data); cube_data = NULL;
01198                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01199                 cpl_propertylist_delete(sub_header); sub_header = NULL;
01200                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01201             } // for j IFUs
01202 
01203             if (detectorimage) {
01204                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01205                                            i, FALSE);
01206                 KMO_TRY_CHECK_ERROR_STATE();
01207 
01208                 KMO_TRY_EXIT_IF_NULL(
01209                     tmp_header = kmclipm_propertylist_load(
01210                                          cpl_frame_get_filename(rec_frame), index));
01211                 KMO_TRY_EXIT_IF_ERROR(
01212                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
01213                                          obs_suffix, tmp_header, dev_flip, FALSE));
01214                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01215 
01216                 if (detImgCube) {
01217                     if (desc1.ex_noise) {
01218                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01219                                                    i, TRUE);
01220                         KMO_TRY_CHECK_ERROR_STATE();
01221                     } else {
01222                         // use same index as for data frame, since input frame
01223                         // has just 3 extensions
01224                     }
01225                     KMO_TRY_EXIT_IF_NULL(
01226                         tmp_header = kmclipm_propertylist_load(
01227                                              cpl_frame_get_filename(rec_frame), index));
01228                     KMO_TRY_EXIT_IF_ERROR(
01229                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01230                                              obs_suffix, tmp_header, dev_flip, TRUE));
01231                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01232                 }
01233             }
01234 
01235             // free memory
01236             cpl_imagelist_delete(cube_data); cube_data = NULL;
01237             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01238             cpl_propertylist_delete(sub_header); sub_header = NULL;
01239             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01240         } // for i devices
01241     }
01242     KMO_CATCH
01243     {
01244         KMO_CATCH_MSG();
01245         ret_val = -1;
01246     }
01247 
01248     kmo_free_fits_desc(&desc1);
01249     kmo_free_fits_desc(&desc2);
01250     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
01251         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01252         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01253     }
01254     cpl_free(my_filter_id); my_filter_id = NULL;
01255     cpl_free(bounds); bounds = NULL;
01256     cpl_propertylist_delete(main_header); main_header = NULL;
01257     cpl_propertylist_delete(sub_header); sub_header = NULL;
01258     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01259     cpl_imagelist_delete(cube_data); cube_data = NULL;
01260     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01261     cpl_free(obs_suffix); obs_suffix = NULL;
01262     cpl_free(suffix); suffix = NULL;
01263     cpl_free(filename_img); filename_img = NULL;
01264     cpl_free(filename_cube); filename_cube = NULL;
01265     if (peaks != NULL ) {cpl_vector_delete(peaks);}
01266     if (ref_spectrum  != NULL ) {cpl_bivector_delete(ref_spectrum);}
01267     sat_mode_msg = FALSE;
01268 
01269     return ret_val;
01270 }
01271