KMOS Pipeline Reference Manual  1.2.3
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.58 2013/07/31 10:40:28 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/07/31 10:40:28 $
00024  * $Revision: 1.58 $
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 "--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     char                *keyword                = NULL,
00395                         *filename_cube          = NULL,
00396                         *filename_img           = NULL,
00397 //                        *fn_lut                 = NULL,
00398                         *suffix                 = NULL,
00399                         *obs_suffix             = NULL,
00400                         *my_filter_id           = NULL,
00401                         *extname                = NULL;
00402     cpl_image           *lcal                   = NULL,
00403                         *det_img_data[KMOS_NR_DETECTORS],
00404                         *det_img_noise[KMOS_NR_DETECTORS],
00405                         *tmp_img                = NULL;
00406     cpl_imagelist       *cube_data              = NULL,
00407                         *cube_noise             = NULL;
00408     cpl_frame           *rec_frame              = NULL,
00409                         *xcal_frame             = NULL,
00410                         *ycal_frame             = NULL,
00411                         *lcal_frame             = NULL,
00412                         *ref_spectrum_frame     = NULL;
00413     cpl_propertylist    *main_header           = NULL,
00414                         *sub_header            = NULL,
00415                         *sub_header_orig       = NULL,
00416                         *actual_sub_header     = NULL,
00417                         *tmp_header            = NULL;
00418     cpl_table           *band_table            = NULL;
00419     gridDefinition      gd;
00420     main_fits_desc      desc1,
00421                         desc2;
00422     cpl_polynomial      *lcorr_coeffs = NULL;
00423 
00424     for (i = 0; i < KMOS_NR_DETECTORS; i++) {
00425         det_img_data[i] = NULL;
00426         det_img_noise[i] = NULL;
00427     }
00428 
00429     KMO_TRY
00430     {
00431         kmo_init_fits_desc(&desc1);
00432         kmo_init_fits_desc(&desc2);
00433 
00434         // --- check input ---
00435         KMO_TRY_ASSURE((parlist != NULL) &&
00436                        (frameset != NULL),
00437                        CPL_ERROR_NULL_INPUT,
00438                        "Not all input data is provided!");
00439 
00440         KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00441                        (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) ||
00442                        (cpl_frameset_count_tags(frameset, ARC_ON) == 1) ||
00443                        (cpl_frameset_count_tags(frameset, OBJECT) == 1) ||
00444                        (cpl_frameset_count_tags(frameset, STD) == 1) ||
00445                        (cpl_frameset_count_tags(frameset, SCIENCE) == 1),
00446                        CPL_ERROR_NULL_INPUT,
00447                        "A data frame (DARK, FLAT_ON, ARC_ON, OBJECT, STD or SCIENCE) must "
00448                        "be provided!");
00449 
00450         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00451                        CPL_ERROR_FILE_NOT_FOUND,
00452                        "XCAL frame missing in frameset!!");
00453 
00454         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00455                        CPL_ERROR_FILE_NOT_FOUND,
00456                        "YCAL frame missing in frameset!!");
00457 
00458         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00459                        CPL_ERROR_FILE_NOT_FOUND,
00460                        "LCAL frame missing in frameset!!");
00461 
00462         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00463                        CPL_ERROR_FILE_NOT_FOUND,
00464                        "WAVE_BAND frame missing in frameset!!");
00465 
00466         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_reconstruct") == 1,
00467                        CPL_ERROR_ILLEGAL_INPUT,
00468                        "Cannot identify RAW and CALIB frames!");
00469 
00470         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, OH_SPEC) == 0 ||
00471                        cpl_frameset_count_tags(frameset, OH_SPEC) == 1,
00472                        CPL_ERROR_ILLEGAL_INPUT,
00473                        "Only a single reference spectrum can be provided!");
00474 
00475         // --- get parameters ---
00476         cpl_msg_info("", "--- Parameter setup for kmo_reconstruct ---");
00477 
00478         KMO_TRY_EXIT_IF_NULL(
00479             imethod = kmo_dfs_get_parameter_string(parlist,
00480                                               "kmos.kmo_reconstruct.imethod"));
00481 
00482         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00483                        (strcmp(imethod, "lwNN") == 0) ||
00484                        (strcmp(imethod, "swNN") == 0) ||
00485                        (strcmp(imethod, "MS") == 0) ||
00486                        (strcmp(imethod, "CS") == 0),
00487                        CPL_ERROR_ILLEGAL_INPUT,
00488                        "imethod must be either \"NN\", \"lwNN\", "
00489                        "\"swNN\", \"MS\" or \"CS\"!");
00490 
00491         KMO_TRY_EXIT_IF_ERROR(
00492             kmo_dfs_print_parameter_help(parlist,
00493                                         "kmos.kmo_reconstruct.imethod"));
00494 
00495         flux = kmo_dfs_get_parameter_bool(parlist,
00496                                           "kmos.kmo_reconstruct.flux");
00497 
00498         KMO_TRY_ASSURE((flux == 0) ||
00499                        (flux == 1),
00500                        CPL_ERROR_ILLEGAL_INPUT,
00501                        "flux must be either FALSE or TRUE!");
00502 
00503         KMO_TRY_EXIT_IF_ERROR(
00504             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.flux"));
00505 
00506         detectorimage = kmo_dfs_get_parameter_bool(parlist,
00507                                           "kmos.kmo_reconstruct.detectorimage");
00508 
00509         KMO_TRY_ASSURE((detectorimage == 0) ||
00510                        (detectorimage == 1),
00511                        CPL_ERROR_ILLEGAL_INPUT,
00512                        "detectorimage must be either 0 or 1 !");
00513 
00514         KMO_TRY_EXIT_IF_ERROR(
00515             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.detectorimage"));
00516 
00517         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00518                 "kmos.kmo_reconstruct.neighborhoodRange");
00519         KMO_TRY_CHECK_ERROR_STATE();
00520         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00521                 CPL_ERROR_ILLEGAL_INPUT,
00522                 "neighborhoodRange must be greater than 0.0");
00523         KMO_TRY_EXIT_IF_ERROR(
00524             kmo_dfs_print_parameter_help(parlist,
00525                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00526 
00527         kmo_band_pars_load(parlist, "kmos.kmo_reconstruct");
00528 
00529         file_extension = kmo_dfs_get_parameter_bool(parlist,
00530                                         "kmos.kmo_reconstruct.file_extension");
00531         KMO_TRY_CHECK_ERROR_STATE();
00532         KMO_TRY_EXIT_IF_ERROR(
00533            kmo_dfs_print_parameter_help(parlist,
00534                                        "kmos.kmo_reconstruct.file_extension"));
00535 
00536         pix_scale = kmo_dfs_get_parameter_double(parlist,
00537                                         "kmos.kmo_reconstruct.pix_scale");
00538         KMO_TRY_CHECK_ERROR_STATE();
00539         KMO_TRY_EXIT_IF_ERROR(
00540            kmo_dfs_print_parameter_help(parlist,
00541                                        "kmos.kmo_reconstruct.pix_scale"));
00542         KMO_TRY_ASSURE((pix_scale >= 0.01) &&
00543                        (pix_scale <= 0.4),
00544                        CPL_ERROR_ILLEGAL_INPUT,
00545                        "pix_scale must be between 0.01 and 0.4 (results in cubes "
00546                        "with 7x7 to 280x280 pixels)!");
00547 
00548         dev_flip = kmo_dfs_get_parameter_bool(parlist,
00549                                            "kmos.kmo_reconstruct.dev_flip");
00550         KMO_TRY_CHECK_ERROR_STATE();
00551         KMO_TRY_EXIT_IF_ERROR(
00552             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.dev_flip"));
00553         KMO_TRY_ASSURE((dev_flip == TRUE) ||
00554                        (dev_flip == FALSE),
00555                        CPL_ERROR_ILLEGAL_INPUT,
00556                        "dev_flip must be TRUE or FALSE!");
00557 
00558         xcal_interpolation = kmo_dfs_get_parameter_bool(parlist,
00559                                            "kmos.kmo_reconstruct.xcal_interpolation");
00560         KMO_TRY_CHECK_ERROR_STATE();
00561         KMO_TRY_EXIT_IF_ERROR(
00562             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.xcal_interpolation"));
00563         KMO_TRY_ASSURE((xcal_interpolation == TRUE) ||
00564                        (xcal_interpolation == FALSE),
00565                        CPL_ERROR_ILLEGAL_INPUT,
00566                        "xcal_interpolation must be TRUE or FALSE!");
00567 
00568 
00569         cpl_msg_info("", "-------------------------------------------");
00570 
00571         // load descriptor and header of data frame to reconstruct
00572         if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00573             input_frame_name = DARK;
00574             output_frame_name = CUBE_DARK;
00575         } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
00576             input_frame_name = FLAT_ON;
00577             output_frame_name = CUBE_FLAT;
00578         } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
00579             input_frame_name = ARC_ON;
00580             output_frame_name = CUBE_ARC;
00581         } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
00582             input_frame_name = OBJECT;
00583             output_frame_name = CUBE_OBJECT;
00584         } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
00585             input_frame_name = STD;
00586             output_frame_name = CUBE_STD;
00587         } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
00588             input_frame_name = SCIENCE;
00589             output_frame_name = CUBE_SCIENCE;
00590         }
00591 
00592         // assure that filters, grating and rotation offsets match for
00593         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
00594         // frames)
00595         // check if filter_id and grating_id match for all detectors
00596         KMO_TRY_EXIT_IF_ERROR(
00597             kmo_check_frame_setup(frameset, XCAL, YCAL,
00598                                        TRUE, FALSE, TRUE));
00599         KMO_TRY_EXIT_IF_ERROR(
00600             kmo_check_frame_setup(frameset, XCAL, LCAL,
00601                                        TRUE, FALSE, TRUE));
00602 
00603 // This check doesn't make sense here since OCS.ROT.NAANGLE is compared.
00604 // When creating the calibration files the RAW exposures needn't have been
00605 // provided in the same order
00606 //        KMO_TRY_EXIT_IF_ERROR(
00607 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00608 //        KMO_TRY_EXIT_IF_ERROR(
00609 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00610 
00611         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00612 
00613             // check if filters, gratings and rotator offset match
00614             // (except for DARK frames)
00615             KMO_TRY_EXIT_IF_ERROR(
00616                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00617                                            TRUE, FALSE, FALSE));
00618 /*
00619             // check if rotator offset don't differ to much
00620             cpl_frame        *f1 = NULL, *f2 = NULL;
00621             cpl_propertylist *h1 = NULL, *h2 = NULL;
00622             char             *kw = NULL;
00623             double           tmp_dbl1 = 0.0, tmp_dbl2 = 0.0;
00624 
00625             KMO_TRY_EXIT_IF_NULL(
00626                 f1 = kmo_dfs_get_frame(frameset, XCAL));
00627 
00628             KMO_TRY_EXIT_IF_NULL(
00629                 f2 = kmo_dfs_get_frame(frameset, input_frame_name));
00630             h1 = kmclipm_propertylist_load(cpl_frame_get_filename(f1), 0);
00631             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00632                 cpl_msg_error("","File not found: %s!",
00633                               cpl_frame_get_filename(f1));
00634                 KMO_TRY_CHECK_ERROR_STATE();
00635             }
00636 
00637             h2 = kmclipm_propertylist_load(cpl_frame_get_filename(f2), 0);
00638             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00639                 cpl_msg_error("","File not found: %s!",
00640                               cpl_frame_get_filename(f2));
00641                 KMO_TRY_CHECK_ERROR_STATE();
00642             }
00643             KMO_TRY_EXIT_IF_NULL(
00644                 kw = cpl_sprintf("%s", ROTANGLE));
00645             tmp_dbl1 = cpl_propertylist_get_double(h1, kw);
00646             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00647                 KMO_TRY_ASSURE(1 == 0,
00648                                CPL_ERROR_ILLEGAL_INPUT,
00649                                "keyword \n%s\n of frame %s is missing!",
00650                                keyword, XCAL);
00651             }
00652 
00653             tmp_dbl2 = cpl_propertylist_get_double(h2, kw);
00654             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00655                 KMO_TRY_ASSURE(1 == 0,
00656                                CPL_ERROR_ILLEGAL_INPUT,
00657                                "keyword \n%s\n of frame %s is missing!",
00658                                keyword, input_frame_name);
00659             }
00660 
00661             // strip angles below 0 deg and above 360 deg
00662             kmclipm_strip_angle(&tmp_dbl1);
00663             kmclipm_strip_angle(&tmp_dbl2);
00664 
00665             if (fabs(tmp_dbl1 - tmp_dbl2) > 30.) {
00666                 if ((fabs(tmp_dbl1) < 0.001) && (tmp_dbl2>330) && (tmp_dbl2<360)) {
00667                     // singularity!
00668                     // we have rot=0 for XCAL and rot>330 | rot<360 for input frame
00669                 } else {
00670                 cpl_msg_warning("","The angle of the calibration files (%g deg) "
00671                                 "and the angle of the frame to reconstruct"
00672                                 " (%g deg) differ by %g deg! Think about using "
00673                                 "calibration files matching better the actual "
00674                                 "rotator offset (ESO OCS ROT NAANGLE)",
00675                                 tmp_dbl1, tmp_dbl2,
00676                                 fabs(tmp_dbl1 - tmp_dbl2));
00677                 }
00678             }
00679 
00680             cpl_propertylist_delete(h1); h1 = NULL;
00681             cpl_propertylist_delete(h2); h2 = NULL;
00682             cpl_free(kw); kw = NULL;
00683 */
00684         }
00685 
00686         if (cpl_frameset_count_tags(frameset, OH_SPEC) != 0) {
00687             KMO_TRY_EXIT_IF_NULL(
00688                     ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC));
00689         }
00690 
00691         KMO_TRY_EXIT_IF_NULL(
00692             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00693         KMO_TRY_EXIT_IF_NULL(
00694             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00695         KMO_TRY_EXIT_IF_NULL(
00696             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00697 
00698         KMO_TRY_EXIT_IF_ERROR(
00699             kmo_check_frame_setup_md5_xycal(frameset));
00700         KMO_TRY_EXIT_IF_ERROR(
00701             kmo_check_frame_setup_md5(frameset));
00702 
00703         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00704         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00705         cpl_msg_info("", "-------------------------------------------");
00706 
00707 
00708         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00709         KMO_TRY_CHECK_ERROR_STATE();
00710 
00711         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00712                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00713                        (desc1.ex_badpix == FALSE) &&
00714                        ((desc1.fits_type == raw_fits) ||
00715                         (desc1.fits_type == f2d_fits)) &&
00716                        (desc1.frame_type == detector_frame),
00717                        CPL_ERROR_ILLEGAL_INPUT,
00718                        "The frame to reconstruct isn't in the correct format!!!"
00719                        "Exactly 3 frames, or 6 with noise are expected!");
00720 
00721         if (!desc1.ex_noise) {
00722             nr_devices = desc1.nr_ext;
00723         } else {
00724             nr_devices = desc1.nr_ext / 2;
00725         }
00726 
00727         // compare descriptor of XCAL and data frame to reconstruct
00728         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00729         KMO_TRY_CHECK_ERROR_STATE();
00730 
00731         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00732                        (desc1.ex_badpix == desc2.ex_badpix) &&
00733                        (desc1.frame_type == desc2.frame_type),
00734                        CPL_ERROR_ILLEGAL_INPUT,
00735                        "XCAL isn't in the correct format!!!");
00736 
00737         kmo_free_fits_desc(&desc2);
00738 
00739         // compare descriptor of YCAL and data frame to reconstruct
00740         kmo_init_fits_desc(&desc2);
00741 
00742         KMO_TRY_EXIT_IF_NULL(
00743             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00744 
00745         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
00746         KMO_TRY_CHECK_ERROR_STATE();
00747 
00748         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00749                        (desc1.ex_badpix == desc2.ex_badpix) &&
00750                        (desc1.frame_type == desc2.frame_type),
00751                        CPL_ERROR_ILLEGAL_INPUT,
00752                        "YCAL isn't in the correct format!!!");
00753 
00754         kmo_free_fits_desc(&desc2);
00755 
00756         // compare descriptor of LCAL and data frame to reconstruct
00757         kmo_init_fits_desc(&desc2);
00758 
00759         KMO_TRY_EXIT_IF_NULL(
00760             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00761 
00762         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
00763         KMO_TRY_CHECK_ERROR_STATE();
00764 
00765         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00766                        (desc1.ex_badpix == desc2.ex_badpix) &&
00767                        (desc1.frame_type == desc2.frame_type),
00768                        CPL_ERROR_ILLEGAL_INPUT,
00769                        "LCAL isn't in the correct format!!!");
00770 
00771         kmo_free_fits_desc(&desc2);
00772 
00773         //
00774         // --- load, update & save primary header ---
00775         //
00776         KMO_TRY_EXIT_IF_NULL(
00777             main_header = kmo_dfs_load_primary_header(frameset,
00778                                                       input_frame_name));
00779 
00780         KMO_TRY_EXIT_IF_NULL(
00781             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00782 
00783         // assert that filters have correct IDs and that all detectors of all
00784         // input frames have the same filter set
00785         for (i = 1; i <= nr_devices; i++) {
00786             // ESO INS FILTi ID
00787             KMO_TRY_EXIT_IF_NULL(
00788                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00789                                       IFU_FILTID_POSTFIX));
00790 
00791             KMO_TRY_EXIT_IF_NULL(
00792                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00793 
00794             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00795                            (strcmp(filter_id, "YJ") == 0) ||
00796                            (strcmp(filter_id, "H") == 0) ||
00797                            (strcmp(filter_id, "K") == 0) ||
00798                            (strcmp(filter_id, "HK") == 0),
00799                            CPL_ERROR_ILLEGAL_INPUT,
00800                            "Filter ID in primary header of LCAL frame must "
00801                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00802                            "\"HK\" !");
00803 
00804             if (strcmp(input_frame_name, DARK) != 0) {
00805                 // dark needn't to be taken with filter!
00806 
00807                 KMO_TRY_EXIT_IF_NULL(
00808                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00809                                                                 keyword));
00810                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00811                                CPL_ERROR_ILLEGAL_INPUT,
00812                                "Filter IDs must be the same for LCAL frame and "
00813                                "the frame to reconstruct!"
00814                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00815                                i, filter_id, input_frame_name, filter_id_tmp);
00816             }
00817             cpl_free(keyword); keyword = NULL;
00818         }
00819         KMO_TRY_EXIT_IF_NULL(
00820             my_filter_id = cpl_strdup(filter_id));
00821         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00822 
00823         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00824         KMO_TRY_CHECK_ERROR_STATE();
00825 
00826         KMO_TRY_EXIT_IF_NULL(
00827             filename_cube = cpl_sprintf("%s", output_frame_name));
00828         KMO_TRY_EXIT_IF_NULL(
00829             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00830         if (file_extension) {
00831             KMO_TRY_EXIT_IF_NULL(
00832                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00833         } else {
00834             KMO_TRY_EXIT_IF_NULL(
00835                 obs_suffix = cpl_sprintf("%s", ""));
00836         }
00837 
00838         KMO_TRY_EXIT_IF_ERROR(
00839             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00840                                      rec_frame, NULL, parlist, cpl_func));
00841 
00842         // setup grid definition, wavelength start and end points will be set
00843         // in the detector loop
00844         KMO_TRY_EXIT_IF_ERROR(
00845             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale));
00846 
00847         KMO_TRY_EXIT_IF_NULL(
00848             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00849 
00850         KMO_TRY_EXIT_IF_NULL(
00851             bounds = kmclipm_extract_bounds(tmp_header));
00852         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00853 
00854         if (detectorimage == TRUE) {
00855             KMO_TRY_EXIT_IF_ERROR(
00856                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00857                                          rec_frame, NULL, parlist, cpl_func));
00858         }
00859 
00860         /* loop through all detectors */
00861         for (i = 1; i <= nr_devices; i++) {
00862             cpl_msg_info("","Processing detector No. %d", i);
00863 
00864             // load lcal
00865             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00866             // doesn't differ too much with different ROTANGLEs.
00867             double rotangle_found;
00868             print_cal_angle_msg_once = FALSE;
00869             KMO_TRY_EXIT_IF_NULL(
00870                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00871                                               FALSE, NULL, &rotangle_found, -1, 0, 0));
00872             if (i==1) {
00873                 print_cal_angle_msg_once = TRUE;
00874             }
00875             char *tmp_band_method = getenv("KMO_BAND_METHOD");
00876             int band_method = 0;
00877             if (tmp_band_method != NULL) {
00878                 band_method = atoi(tmp_band_method);
00879             }
00880 
00881             KMO_TRY_EXIT_IF_NULL(
00882                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00883 
00884             KMO_TRY_EXIT_IF_ERROR(
00885                 kmclipm_setup_grid_band_lcal(&gd, lcal, my_filter_id,
00886                                              band_method, band_table));
00887             cpl_table_delete(band_table); band_table = NULL;
00888 
00889             cpl_image_delete(lcal); lcal = NULL;
00890 
00891             if (detectorimage == TRUE) {
00892                 KMO_TRY_EXIT_IF_NULL(
00893                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00894                                                       gd.l.dim, CPL_TYPE_FLOAT));
00895                 KMO_TRY_EXIT_IF_NULL(
00896                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00897 
00898                 KMO_TRY_EXIT_IF_NULL(
00899                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00900                                                       gd.l.dim, CPL_TYPE_FLOAT));
00901                 KMO_TRY_EXIT_IF_NULL(
00902                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00903             }
00904 
00905 
00906             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00907                 /* update sub-header */
00908                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00909 
00910                 /* load raw image and sub-header*/
00911                 KMO_TRY_EXIT_IF_NULL(
00912                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00913                                                          i, FALSE));
00914                 KMO_TRY_EXIT_IF_NULL(
00915                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00916 
00917                 // check if IFU is valid according to main header keywords &
00918                 // calibration files
00919 
00920                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00921                     KMO_TRY_EXIT_IF_NULL(
00922                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00923                                               IFU_VALID_POSTFIX));
00924                     KMO_TRY_CHECK_ERROR_STATE();
00925                     cpl_propertylist_get_string(main_header, keyword);
00926                     cpl_free(keyword); keyword = NULL;
00927                 } else {
00928                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00929                     // reconstructed
00930                     cpl_propertylist_get_string(main_header, "ggg");
00931                 }
00932 
00933                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00934                     (bounds[2*(ifu_nr-1)] != -1) &&
00935                     (bounds[2*(ifu_nr-1)+1] != -1))
00936                 {
00937                     cpl_error_reset();
00938                     // IFU is valid
00939                     actual_sub_header = sub_header;
00940 
00941                     //
00942                     // calc WCS & update subheader
00943                     //
00944                     KMO_TRY_EXIT_IF_ERROR(
00945                         kmo_calc_wcs_gd(main_header, actual_sub_header, ifu_nr, gd));
00946 
00947                     KMO_TRY_EXIT_IF_ERROR(
00948                         kmclipm_update_property_int(actual_sub_header,
00949                                                     NAXIS, 3,
00950                                                     "number of data axes"));
00951                     KMO_TRY_EXIT_IF_ERROR(
00952                         kmclipm_update_property_int(actual_sub_header,
00953                                                     NAXIS1, gd.x.dim,
00954                                                     "length of data axis 1"));
00955                     KMO_TRY_EXIT_IF_ERROR(
00956                         kmclipm_update_property_int(actual_sub_header,
00957                                                     NAXIS2, gd.y.dim,
00958                                                     "length of data axis 2"));
00959                     KMO_TRY_EXIT_IF_ERROR(
00960                         kmclipm_update_property_int(actual_sub_header,
00961                                                     NAXIS3, gd.l.dim,
00962                                                     "length of data axis 3"));
00963 
00964                     // reconstruct data and noise (if available)
00965 //                    if (j == 0) {
00966 //                        sat_mode_msg = FALSE;
00967 //                    } else {
00968 //                        sat_mode_msg = TRUE;
00969 //                    }
00970                     KMO_TRY_EXIT_IF_ERROR(
00971                         kmo_reconstruct_sci(ifu_nr,
00972                                             bounds[2*(ifu_nr-1)],
00973                                             bounds[2*(ifu_nr-1)+1],
00974                                             rec_frame,
00975                                             input_frame_name,
00976                                             NULL,
00977                                             NULL,
00978                                             NULL,
00979                                             xcal_frame,
00980                                             ycal_frame,
00981                                             lcal_frame,
00982                                             NULL,
00983                                             &gd,
00984                                             &cube_data,
00985                                             &cube_noise,
00986                                             flux,
00987                                             background,
00988                                             xcal_interpolation));
00989 
00990                     if (ref_spectrum_frame != NULL && cube_data != NULL) {
00991                         KMO_TRY_EXIT_IF_NULL(
00992                             lcorr_coeffs = kmo_lcorr_get(cube_data,
00993                                                          actual_sub_header,
00994                                                          ref_spectrum_frame,
00995                                                          gd,
00996                                                          my_filter_id,
00997                                                          ifu_nr));
00998 
00999                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01000                         if (cube_noise != NULL) {
01001                             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01002                         }
01003                         KMO_TRY_EXIT_IF_ERROR(
01004                             kmo_reconstruct_sci(ifu_nr,
01005                                                 bounds[2*(ifu_nr-1)],
01006                                                 bounds[2*(ifu_nr-1)+1],
01007                                                 rec_frame,
01008                                                 input_frame_name,
01009                                                 NULL,
01010                                                 NULL,
01011                                                 NULL,
01012                                                 xcal_frame,
01013                                                 ycal_frame,
01014                                                 lcal_frame,
01015                                                 lcorr_coeffs,
01016                                                 &gd,
01017                                                 &cube_data,
01018                                                 &cube_noise,
01019                                                 flux,
01020                                                 background,
01021                                                 xcal_interpolation));
01022 /*
01023  // show that lambda correction improved the data cube, a second one would improve even more
01024 
01025                         cpl_bivector *obj_spectrum2, *obj_spectrum3;
01026                         cpl_polynomial *lcorr_coeffs2, *lcorr_coeffs3;
01027                         KMO_TRY_EXIT_IF_NULL(
01028                                 obj_spectrum2 = kmo_lcorr_extract_spectrum(
01029                                         cube_data, actual_sub_header, 0.8, NULL));
01030 
01031                         KMO_TRY_EXIT_IF_NULL(
01032                                 lcorr_coeffs2 = kmo_lcorr_crosscorrelate_spectra(
01033                                         obj_spectrum2, ref_spectrum, peaks, 0.002));
01034 
01035                         cpl_bivector_delete(obj_spectrum2);
01036 
01037                         coeff_dump[0] = 0;
01038                         for (ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs2) && ic < max_coeffs; ic++) {
01039                             pows[0] = ic;
01040                             coeff_string = cpl_sprintf(" %*g,",
01041                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs2,pows));
01042                             strncat(coeff_dump, coeff_string, format_width);
01043                             cpl_free(coeff_string);
01044                             double c1 =  cpl_polynomial_get_coeff(lcorr_coeffs,pows);
01045                             double c2 =  cpl_polynomial_get_coeff(lcorr_coeffs2,pows);
01046                             cpl_polynomial_set_coeff(lcorr_coeffs, pows, c1+c2);
01047                         }
01048                         cpl_msg_debug("","Lambda correction coeffs for ifu %d %s",ifu_nr, coeff_dump);
01049                         cpl_polynomial_delete(lcorr_coeffs2); lcorr_coeffs2=NULL;
01050 
01051                         cpl_imagelist_delete(cube_data); cube_data = NULL;
01052                         cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01053                         KMO_TRY_EXIT_IF_ERROR(
01054                             kmo_reconstruct_sci(ifu_nr,
01055                                                 bounds[2*(ifu_nr-1)],
01056                                                 bounds[2*(ifu_nr-1)+1],
01057                                                 rec_frame,
01058                                                 input_frame_name,
01059                                                 NULL,
01060                                                 NULL,
01061                                                 NULL,
01062                                                 xcal_frame,
01063                                                 ycal_frame,
01064                                                 lcal_frame,
01065                                                 lcorr_coeffs,
01066                                                 &gd,
01067                                                 &cube_data,
01068                                                 &cube_noise,
01069                                                 flux,
01070                                                 background,
01071                                                 xcal_interpolation));
01072 
01073                         KMO_TRY_EXIT_IF_NULL(
01074                                 obj_spectrum3 = kmo_lcorr_extract_spectrum(
01075                                         cube_data, actual_sub_header, 0.8, NULL));
01076 
01077                         KMO_TRY_EXIT_IF_NULL(
01078                                 lcorr_coeffs3 = kmo_lcorr_crosscorrelate_spectra(
01079                                         obj_spectrum3, ref_spectrum, peaks, 0.002));
01080 
01081                         cpl_bivector_delete(obj_spectrum3);
01082 
01083                         coeff_dump[0] = 0;
01084                         for (ic=0; ic<=cpl_polynomial_get_degree(lcorr_coeffs3) && ic < max_coeffs; ic++) {
01085                             pows[0] = ic;
01086                             coeff_string = cpl_sprintf(" %*g,",
01087                                     format_width-2, cpl_polynomial_get_coeff(lcorr_coeffs3,pows));
01088                             strncat(coeff_dump, coeff_string, format_width);
01089                             cpl_free(coeff_string);
01090                         }
01091                         cpl_msg_debug("","Lambda correction coeffs for iFu %d %s",ifu_nr, coeff_dump);
01092                         cpl_polynomial_delete(lcorr_coeffs3); lcorr_coeffs3=NULL;
01093 */
01094                         cpl_polynomial_delete(lcorr_coeffs); lcorr_coeffs = NULL;
01095 
01096                     }
01097 
01098                     // scale flux according to pixel_scale
01099                     KMO_TRY_EXIT_IF_NULL(
01100                         tmp_img = cpl_imagelist_get(cube_data, 0));
01101                     double scaling = (cpl_image_get_size_x(tmp_img)*cpl_image_get_size_y(tmp_img)) /
01102                                      (KMOS_SLITLET_X*KMOS_SLITLET_Y);
01103                     KMO_TRY_EXIT_IF_ERROR(
01104                         cpl_imagelist_divide_scalar(cube_data, scaling));
01105                     if (cube_noise != NULL) {
01106                         KMO_TRY_EXIT_IF_ERROR(
01107                             cpl_imagelist_divide_scalar(cube_noise, scaling));
01108                     }
01109                 } else {
01110                     // IFU is invalid
01111                     actual_sub_header = sub_header_orig;
01112                     cpl_error_reset();
01113                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
01114 
01115                 if (detectorimage) {
01116                     if (cube_data != NULL) {
01117                         for (l = 0; l < gd.l.dim; l++) {
01118                             KMO_TRY_EXIT_IF_NULL(
01119                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
01120                             for (y = 0; y < gd.y.dim; y++) {
01121                                 for (x = 0; x < gd.x.dim; x++) {
01122                                     int ix = x +
01123                                              y * gd.x.dim +
01124                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01125                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01126                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
01127                                 }
01128                             }
01129                         }
01130                     }
01131                     if (cube_noise != NULL) {
01132                         if (detectorimage) {
01133                             detImgCube = TRUE;
01134                         }
01135                         for (l = 0; l < gd.l.dim; l++) {
01136                             KMO_TRY_EXIT_IF_NULL(
01137                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
01138                             for (y = 0; y < gd.y.dim; y++) {
01139                                 for (x = 0; x < gd.x.dim; x++) {
01140                                     int ix = x +
01141                                              y * gd.x.dim +
01142                                              j * gd.x.dim*gd.y.dim +     //IFU offset
01143                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
01144                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
01145                                 }
01146                             }
01147                         }
01148                     }
01149                 }
01150 
01151                 // save output
01152                 KMO_TRY_EXIT_IF_NULL(
01153                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
01154                                                   EXT_DATA));
01155 
01156                 KMO_TRY_EXIT_IF_ERROR(
01157                     kmclipm_update_property_string(actual_sub_header,
01158                                             EXTNAME,
01159                                             extname,
01160                                             "FITS extension name"));
01161 
01162                 cpl_free(extname); extname = NULL;
01163 
01164                 KMO_TRY_EXIT_IF_ERROR(
01165                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
01166                                       actual_sub_header, 0./0.));
01167 
01168                 if (cube_noise != NULL) {
01169                     KMO_TRY_EXIT_IF_NULL(
01170                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01171                                                       EXT_NOISE));
01172 
01173                     KMO_TRY_EXIT_IF_ERROR(
01174                         kmclipm_update_property_string(actual_sub_header,
01175                                                 EXTNAME,
01176                                                 extname,
01177                                                 "FITS extension name"));
01178 
01179                     cpl_free(extname); extname = NULL;
01180 
01181                     KMO_TRY_EXIT_IF_ERROR(
01182                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
01183                                           actual_sub_header, 0./0.));
01184                 }
01185 
01186                 cpl_imagelist_delete(cube_data); cube_data = NULL;
01187                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01188                 cpl_propertylist_delete(sub_header); sub_header = NULL;
01189                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01190             } // for j IFUs
01191 
01192             if (detectorimage) {
01193                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01194                                            i, FALSE);
01195                 KMO_TRY_CHECK_ERROR_STATE();
01196 
01197                 KMO_TRY_EXIT_IF_NULL(
01198                     tmp_header = kmclipm_propertylist_load(
01199                                          cpl_frame_get_filename(rec_frame), index));
01200                 KMO_TRY_EXIT_IF_ERROR(
01201                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
01202                                          obs_suffix, tmp_header, dev_flip, FALSE));
01203                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01204 
01205                 if (detImgCube) {
01206                     if (desc1.ex_noise) {
01207                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01208                                                    i, TRUE);
01209                         KMO_TRY_CHECK_ERROR_STATE();
01210                     } else {
01211                         // use same index as for data frame, since input frame
01212                         // has just 3 extensions
01213                     }
01214                     KMO_TRY_EXIT_IF_NULL(
01215                         tmp_header = kmclipm_propertylist_load(
01216                                              cpl_frame_get_filename(rec_frame), index));
01217                     KMO_TRY_EXIT_IF_ERROR(
01218                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01219                                              obs_suffix, tmp_header, dev_flip, TRUE));
01220                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01221                 }
01222             }
01223 
01224             // free memory
01225             cpl_imagelist_delete(cube_data); cube_data = NULL;
01226             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01227             cpl_propertylist_delete(sub_header); sub_header = NULL;
01228             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01229         } // for i devices
01230     }
01231     KMO_CATCH
01232     {
01233         KMO_CATCH_MSG();
01234         ret_val = -1;
01235     }
01236 
01237     kmo_free_fits_desc(&desc1);
01238     kmo_free_fits_desc(&desc2);
01239     for (i = 0; i < KMOS_NR_DETECTORS; i++) {
01240         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01241         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01242     }
01243     cpl_free(my_filter_id); my_filter_id = NULL;
01244     cpl_free(bounds); bounds = NULL;
01245     cpl_propertylist_delete(main_header); main_header = NULL;
01246     cpl_propertylist_delete(sub_header); sub_header = NULL;
01247     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01248     cpl_imagelist_delete(cube_data); cube_data = NULL;
01249     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01250     cpl_free(obs_suffix); obs_suffix = NULL;
01251     cpl_free(suffix); suffix = NULL;
01252     cpl_free(filename_img); filename_img = NULL;
01253     cpl_free(filename_cube); filename_cube = NULL;
01254 //    sat_mode_msg = FALSE;
01255 
01256     return ret_val;
01257 }
01258