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