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