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