KMOS Pipeline Reference Manual  1.3.0
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, OH_SPEC) > 0) {
00569             KMO_TRY_EXIT_IF_ERROR(kmo_check_oh_spec_setup(frameset, XCAL));
00570         }
00571 
00572         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00573             // check if filters, gratings and rotator offset match
00574             // (except for DARK frames)
00575             KMO_TRY_EXIT_IF_ERROR(
00576                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00577                                            TRUE, FALSE, FALSE));
00578         }
00579 
00580         KMO_TRY_EXIT_IF_NULL(
00581             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00582         KMO_TRY_EXIT_IF_NULL(
00583             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00584         KMO_TRY_EXIT_IF_NULL(
00585             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00586 
00587         KMO_TRY_EXIT_IF_ERROR(
00588             kmo_check_frame_setup_md5_xycal(frameset));
00589         KMO_TRY_EXIT_IF_ERROR(
00590             kmo_check_frame_setup_md5(frameset));
00591 
00592         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00593         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00594         cpl_msg_info("", "-------------------------------------------");
00595 
00596         KMO_TRY_EXIT_IF_NULL(
00597             main_header = kmo_dfs_load_primary_header(frameset,
00598                                                       input_frame_name));
00599 
00600         if (cpl_frameset_count_tags(frameset, OH_SPEC) != 0) {
00601             if (cpl_propertylist_has(main_header, ORIGFILE)) {
00602                 KMO_TRY_EXIT_IF_NULL(
00603                     tmp_str = cpl_propertylist_get_string(main_header, ORIGFILE));
00604                 if (strstr(tmp_str, "OBS") != NULL) {
00605                     // we are reconstructing an OBS-frame, allow OH_SPEC correction
00606                     KMO_TRY_EXIT_IF_NULL(
00607                         ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC));
00608                 } else {
00609                     cpl_msg_warning("", "Supplied OH_SPEC is ignored since a calibration frame is being reconstructed.");
00610                 }
00611             } else {
00612                 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);
00613                 KMO_TRY_EXIT_IF_NULL(
00614                     ref_spectrum_frame = kmo_dfs_get_frame(frameset, OH_SPEC));
00615             }
00616         }
00617 
00618         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00619         KMO_TRY_CHECK_ERROR_STATE();
00620 
00621         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00622                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00623                        (desc1.ex_badpix == FALSE) &&
00624                        ((desc1.fits_type == raw_fits) ||
00625                         (desc1.fits_type == f2d_fits)) &&
00626                        (desc1.frame_type == detector_frame),
00627                        CPL_ERROR_ILLEGAL_INPUT,
00628                        "The frame to reconstruct isn't in the correct format!!!"
00629                        "Exactly 3 frames, or 6 with noise are expected!");
00630 
00631         if (!desc1.ex_noise) {
00632             nr_devices = desc1.nr_ext;
00633         } else {
00634             nr_devices = desc1.nr_ext / 2;
00635         }
00636 
00637         // compare descriptor of XCAL and data frame to reconstruct
00638         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00639         KMO_TRY_CHECK_ERROR_STATE();
00640 
00641         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00642                        (desc1.ex_badpix == desc2.ex_badpix) &&
00643                        (desc1.frame_type == desc2.frame_type),
00644                        CPL_ERROR_ILLEGAL_INPUT,
00645                        "XCAL isn't in the correct format!!!");
00646 
00647         kmo_free_fits_desc(&desc2);
00648 
00649         // compare descriptor of YCAL and data frame to reconstruct
00650         kmo_init_fits_desc(&desc2);
00651 
00652         KMO_TRY_EXIT_IF_NULL(
00653             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00654 
00655         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
00656         KMO_TRY_CHECK_ERROR_STATE();
00657 
00658         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00659                        (desc1.ex_badpix == desc2.ex_badpix) &&
00660                        (desc1.frame_type == desc2.frame_type),
00661                        CPL_ERROR_ILLEGAL_INPUT,
00662                        "YCAL isn't in the correct format!!!");
00663 
00664         kmo_free_fits_desc(&desc2);
00665 
00666         // compare descriptor of LCAL and data frame to reconstruct
00667         kmo_init_fits_desc(&desc2);
00668 
00669         KMO_TRY_EXIT_IF_NULL(
00670             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00671 
00672         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
00673         KMO_TRY_CHECK_ERROR_STATE();
00674 
00675         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00676                        (desc1.ex_badpix == desc2.ex_badpix) &&
00677                        (desc1.frame_type == desc2.frame_type),
00678                        CPL_ERROR_ILLEGAL_INPUT,
00679                        "LCAL isn't in the correct format!!!");
00680 
00681         kmo_free_fits_desc(&desc2);
00682 
00683         //
00684         // --- update & save primary header ---
00685         //
00686         KMO_TRY_EXIT_IF_NULL(
00687             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00688 
00689         // assert that filters have correct IDs and that all detectors of all
00690         // input frames have the same filter set
00691         for (i = 1; i <= nr_devices; i++) {
00692             // ESO INS FILTi ID
00693             KMO_TRY_EXIT_IF_NULL(
00694                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00695                                       IFU_FILTID_POSTFIX));
00696 
00697             KMO_TRY_EXIT_IF_NULL(
00698                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00699 
00700             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00701                            (strcmp(filter_id, "YJ") == 0) ||
00702                            (strcmp(filter_id, "H") == 0) ||
00703                            (strcmp(filter_id, "K") == 0) ||
00704                            (strcmp(filter_id, "HK") == 0),
00705                            CPL_ERROR_ILLEGAL_INPUT,
00706                            "Filter ID in primary header of LCAL frame must "
00707                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00708                            "\"HK\" !");
00709 
00710             if (strcmp(input_frame_name, DARK) != 0) {
00711                 // dark needn't to be taken with filter!
00712 
00713                 KMO_TRY_EXIT_IF_NULL(
00714                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00715                                                                 keyword));
00716                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00717                                CPL_ERROR_ILLEGAL_INPUT,
00718                                "Filter IDs must be the same for LCAL frame and "
00719                                "the frame to reconstruct!"
00720                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00721                                i, filter_id, input_frame_name, filter_id_tmp);
00722             }
00723             cpl_free(keyword); keyword = NULL;
00724         }
00725         KMO_TRY_EXIT_IF_NULL(
00726             my_filter_id = cpl_strdup(filter_id));
00727         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00728 
00729         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00730         KMO_TRY_CHECK_ERROR_STATE();
00731 
00732         KMO_TRY_EXIT_IF_NULL(
00733             filename_cube = cpl_sprintf("%s", output_frame_name));
00734         KMO_TRY_EXIT_IF_NULL(
00735             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00736         if (file_extension) {
00737             KMO_TRY_EXIT_IF_NULL(
00738                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00739         } else {
00740             KMO_TRY_EXIT_IF_NULL(
00741                 obs_suffix = cpl_sprintf("%s", ""));
00742         }
00743 
00744         KMO_TRY_EXIT_IF_ERROR(
00745             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00746                                      rec_frame, NULL, parlist, cpl_func));
00747 
00748         // setup grid definition, wavelength start and end points will be set
00749         // in the detector loop
00750         KMO_TRY_EXIT_IF_ERROR(
00751             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale, 0.));
00752 
00753         KMO_TRY_EXIT_IF_NULL(
00754             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00755 
00756         KMO_TRY_EXIT_IF_NULL(
00757             bounds = kmclipm_extract_bounds(tmp_header));
00758         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00759 
00760         if (detectorimage == TRUE) {
00761             KMO_TRY_EXIT_IF_ERROR(
00762                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00763                                          rec_frame, NULL, parlist, cpl_func));
00764         }
00765 
00766         /* loop through all detectors */
00767         for (i = 1; i <= nr_devices; i++) {
00768             cpl_msg_info("","Processing detector No. %d", i);
00769 
00770             // load lcal
00771             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00772             // doesn't differ too much with different ROTANGLEs.
00773             double rotangle_found;
00774             print_cal_angle_msg_once = FALSE;
00775             print_xcal_angle_msg_once = FALSE;
00776             KMO_TRY_EXIT_IF_NULL(
00777                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00778                                               FALSE, NULL, &rotangle_found, -1, 0, 0));
00779             if (i==1) {
00780                 print_cal_angle_msg_once = TRUE;
00781                 print_xcal_angle_msg_once = TRUE;
00782             }
00783 
00784             KMO_TRY_EXIT_IF_NULL(
00785                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00786 
00787             KMO_TRY_EXIT_IF_ERROR(
00788                 kmclipm_setup_grid_band_lcal(&gd, my_filter_id,
00789                                              band_table));
00790             cpl_table_delete(band_table); band_table = NULL;
00791 
00792             cpl_image_delete(lcal); lcal = NULL;
00793 
00794             if (detectorimage == TRUE) {
00795                 KMO_TRY_EXIT_IF_NULL(
00796                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00797                                                       gd.l.dim, CPL_TYPE_FLOAT));
00798                 KMO_TRY_EXIT_IF_NULL(
00799                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00800 
00801                 KMO_TRY_EXIT_IF_NULL(
00802                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00803                                                       gd.l.dim, CPL_TYPE_FLOAT));
00804                 KMO_TRY_EXIT_IF_NULL(
00805                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00806             }
00807 
00808 
00809             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00810                 /* update sub-header */
00811                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00812 
00813                 /* load raw image and sub-header*/
00814                 KMO_TRY_EXIT_IF_NULL(
00815                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00816                                                          i, FALSE));
00817                 KMO_TRY_EXIT_IF_NULL(
00818                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00819 
00820                 // check if IFU is valid according to main header keywords &
00821                 // calibration files
00822 
00823                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00824                     KMO_TRY_EXIT_IF_NULL(
00825                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00826                                               IFU_VALID_POSTFIX));
00827                     KMO_TRY_CHECK_ERROR_STATE();
00828                     cpl_propertylist_get_string(main_header, keyword);
00829                     cpl_free(keyword); keyword = NULL;
00830                 } else {
00831                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00832                     // reconstructed
00833                     cpl_propertylist_get_string(main_header, "ggg");
00834                 }
00835 
00836                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00837                     (bounds[2*(ifu_nr-1)] != -1) &&
00838                     (bounds[2*(ifu_nr-1)+1] != -1))
00839                 {
00840                     cpl_error_reset();
00841                     // IFU is valid
00842                     actual_sub_header = sub_header;
00843 
00844                     //
00845                     // calc WCS & update subheader
00846                     //
00847                     KMO_TRY_EXIT_IF_ERROR(
00848                         kmo_calc_wcs_gd(main_header, actual_sub_header, ifu_nr, gd));
00849 
00850                     KMO_TRY_EXIT_IF_ERROR(
00851                         kmclipm_update_property_int(actual_sub_header,
00852                                                     NAXIS, 3,
00853                                                     "number of data axes"));
00854                     KMO_TRY_EXIT_IF_ERROR(
00855                         kmclipm_update_property_int(actual_sub_header,
00856                                                     NAXIS1, gd.x.dim,
00857                                                     "length of data axis 1"));
00858                     KMO_TRY_EXIT_IF_ERROR(
00859                         kmclipm_update_property_int(actual_sub_header,
00860                                                     NAXIS2, gd.y.dim,
00861                                                     "length of data axis 2"));
00862                     KMO_TRY_EXIT_IF_ERROR(
00863                         kmclipm_update_property_int(actual_sub_header,
00864                                                     NAXIS3, gd.l.dim,
00865                                                     "length of data axis 3"));
00866 
00867                     // reconstruct data and noise (if available)
00868 //                    if (j == 0) {
00869 //                        sat_mode_msg = FALSE;
00870 //                    } else {
00871 //                        sat_mode_msg = TRUE;
00872 //                    }
00873                     KMO_TRY_EXIT_IF_ERROR(
00874                         kmo_reconstruct_sci(ifu_nr,
00875                                             bounds[2*(ifu_nr-1)],
00876                                             bounds[2*(ifu_nr-1)+1],
00877                                             rec_frame,
00878                                             input_frame_name,
00879                                             NULL,
00880                                             NULL,
00881                                             NULL,
00882                                             xcal_frame,
00883                                             ycal_frame,
00884                                             lcal_frame,
00885                                             NULL,
00886                                             NULL,
00887                                             &gd,
00888                                             &cube_data,
00889                                             &cube_noise,
00890                                             flux,
00891                                             background,
00892                                             xcal_interpolation));
00893 
00894                     if (ref_spectrum_frame != NULL && cube_data != NULL) {
00895                         KMO_TRY_EXIT_IF_NULL(
00896                             lcorr_coeffs = kmo_lcorr_get(cube_data,
00897                                                          actual_sub_header,
00898                                                          ref_spectrum_frame,
00899                                                          gd,
00900                                                          my_filter_id,
00901                                                          ifu_nr));
00902 
00903                         cpl_imagelist_delete(cube_data); cube_data = NULL;
00904                         if (cube_noise != NULL) {
00905                             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
00906                         }
00907                         KMO_TRY_EXIT_IF_ERROR(
00908                             kmo_reconstruct_sci(ifu_nr,
00909                                                 bounds[2*(ifu_nr-1)],
00910                                                 bounds[2*(ifu_nr-1)+1],
00911                                                 rec_frame,
00912                                                 input_frame_name,
00913                                                 NULL,
00914                                                 NULL,
00915                                                 NULL,
00916                                                 xcal_frame,
00917                                                 ycal_frame,
00918                                                 lcal_frame,
00919                                                 lcorr_coeffs,
00920                                                 NULL,
00921                                                 &gd,
00922                                                 &cube_data,
00923                                                 &cube_noise,
00924                                                 flux,
00925                                                 background,
00926                                                 xcal_interpolation));
00927                         cpl_polynomial_delete(lcorr_coeffs); lcorr_coeffs = NULL;
00928 
00929                     }
00930 
00931                     // scale flux according to pixel_scale
00932                     KMO_TRY_EXIT_IF_NULL(
00933                         tmp_img = cpl_imagelist_get(cube_data, 0));
00934                     double scaling = (cpl_image_get_size_x(tmp_img)*cpl_image_get_size_y(tmp_img)) /
00935                                      (KMOS_SLITLET_X*KMOS_SLITLET_Y);
00936                     KMO_TRY_EXIT_IF_ERROR(
00937                         cpl_imagelist_divide_scalar(cube_data, scaling));
00938                     if (cube_noise != NULL) {
00939                         KMO_TRY_EXIT_IF_ERROR(
00940                             cpl_imagelist_divide_scalar(cube_noise, scaling));
00941                     }
00942                 } else {
00943                     // IFU is invalid
00944                     actual_sub_header = sub_header_orig;
00945                     cpl_error_reset();
00946                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
00947 
00948                 if (detectorimage) {
00949                     if (cube_data != NULL) {
00950                         for (l = 0; l < gd.l.dim; l++) {
00951                             KMO_TRY_EXIT_IF_NULL(
00952                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
00953                             for (y = 0; y < gd.y.dim; y++) {
00954                                 for (x = 0; x < gd.x.dim; x++) {
00955                                     int ix = x +
00956                                              y * gd.x.dim +
00957                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00958                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00959                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
00960                                 }
00961                             }
00962                         }
00963                     }
00964                     if (cube_noise != NULL) {
00965                         if (detectorimage) {
00966                             detImgCube = TRUE;
00967                         }
00968                         for (l = 0; l < gd.l.dim; l++) {
00969                             KMO_TRY_EXIT_IF_NULL(
00970                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
00971                             for (y = 0; y < gd.y.dim; y++) {
00972                                 for (x = 0; x < gd.x.dim; x++) {
00973                                     int ix = x +
00974                                              y * gd.x.dim +
00975                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00976                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00977                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
00978                                 }
00979                             }
00980                         }
00981                     }
00982                 }
00983 
00984                 // save output
00985                 KMO_TRY_EXIT_IF_NULL(
00986                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
00987                                                   EXT_DATA));
00988 
00989                 KMO_TRY_EXIT_IF_ERROR(
00990                     kmclipm_update_property_string(actual_sub_header,
00991                                             EXTNAME,
00992                                             extname,
00993                                             "FITS extension name"));
00994 
00995                 cpl_free(extname); extname = NULL;
00996 
00997                 KMO_TRY_EXIT_IF_ERROR(
00998                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
00999                                       actual_sub_header, 0./0.));
01000 
01001                 if (cube_noise != NULL) {
01002                     KMO_TRY_EXIT_IF_NULL(
01003                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01004                                                       EXT_NOISE));
01005 
01006                     KMO_TRY_EXIT_IF_ERROR(
01007                         kmclipm_update_property_string(actual_sub_header,
01008                                                 EXTNAME,
01009                                                 extname,
01010                                                 "FITS extension name"));
01011 
01012                     cpl_free(extname); extname = NULL;
01013 
01014                     KMO_TRY_EXIT_IF_ERROR(
01015                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
01016                                           actual_sub_header, 0./0.));
01017                 }
01018 
01019                 cpl_imagelist_delete(cube_data); cube_data = NULL;
01020                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01021                 cpl_propertylist_delete(sub_header); sub_header = NULL;
01022                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01023             } // for j IFUs
01024 
01025             if (detectorimage) {
01026                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01027                                            i, FALSE);
01028                 KMO_TRY_CHECK_ERROR_STATE();
01029 
01030                 KMO_TRY_EXIT_IF_NULL(
01031                     tmp_header = kmclipm_propertylist_load(
01032                                          cpl_frame_get_filename(rec_frame), index));
01033                 KMO_TRY_EXIT_IF_ERROR(
01034                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
01035                                          obs_suffix, tmp_header, FALSE, FALSE));
01036                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01037 
01038                 if (detImgCube) {
01039                     if (desc1.ex_noise) {
01040                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01041                                                    i, TRUE);
01042                         KMO_TRY_CHECK_ERROR_STATE();
01043                     } else {
01044                         // use same index as for data frame, since input frame
01045                         // has just 3 extensions
01046                     }
01047                     KMO_TRY_EXIT_IF_NULL(
01048                         tmp_header = kmclipm_propertylist_load(
01049                                              cpl_frame_get_filename(rec_frame), index));
01050                     KMO_TRY_EXIT_IF_ERROR(
01051                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01052                                              obs_suffix, tmp_header,
01053                                              FALSE, TRUE));
01054                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01055                 }
01056             }
01057 
01058             // free memory
01059             cpl_imagelist_delete(cube_data); cube_data = NULL;
01060             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01061             cpl_propertylist_delete(sub_header); sub_header = NULL;
01062             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01063         } // for i devices
01064     }
01065     KMO_CATCH
01066     {
01067         KMO_CATCH_MSG();
01068         ret_val = -1;
01069     }
01070 
01071     kmo_free_fits_desc(&desc1);
01072     kmo_free_fits_desc(&desc2);
01073     for (i = 0; i < KMOS_NR_DETECTORS; i++) {
01074         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01075         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01076     }
01077     cpl_free(my_filter_id); my_filter_id = NULL;
01078     cpl_free(bounds); bounds = NULL;
01079     cpl_propertylist_delete(main_header); main_header = NULL;
01080     cpl_propertylist_delete(sub_header); sub_header = NULL;
01081     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01082     cpl_imagelist_delete(cube_data); cube_data = NULL;
01083     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01084     cpl_free(obs_suffix); obs_suffix = NULL;
01085     cpl_free(suffix); suffix = NULL;
01086     cpl_free(filename_img); filename_img = NULL;
01087     cpl_free(filename_cube); filename_cube = NULL;
01088 
01089     return ret_val;
01090 }
01091