KMOS Pipeline Reference Manual  1.1.1
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.42 2013/04/18 12:55:54 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/04/18 12:55:54 $
00024  * $Revision: 1.42 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "kmo_utils.h"
00042 #include "kmo_functions.h"
00043 #include "kmo_priv_reconstruct.h"
00044 #include "kmo_priv_functions.h"
00045 #include "kmo_cpl_extensions.h"
00046 #include "kmo_dfs.h"
00047 #include "kmo_error.h"
00048 #include "kmo_utils.h"
00049 #include "kmo_constants.h"
00050 #include "kmo_debug.h"
00051 
00052 /*-----------------------------------------------------------------------------
00053  *                          Functions prototypes
00054  *----------------------------------------------------------------------------*/
00055 
00056 static int kmo_reconstruct_create(cpl_plugin *);
00057 static int kmo_reconstruct_exec(cpl_plugin *);
00058 static int kmo_reconstruct_destroy(cpl_plugin *);
00059 static int kmo_reconstruct(cpl_parameterlist *, cpl_frameset *);
00060 
00061 /*-----------------------------------------------------------------------------
00062  *                          Static variables
00063  *----------------------------------------------------------------------------*/
00064 
00065 static char kmo_reconstruct_description[] =
00066 "Data with or without noise is reconstructed into a cube using the calibration\n"
00067 "frames XCAL, YCAL and LCAL. XCAL and YCAL are generated using recipe kmo_flat,\n"
00068 "LCAL is generated using recipe kmo_wave_cal.\n"
00069 "The input data can contain noise extensions and will be reconstructed into\n"
00070 "additional extensions.\n"
00071 "\n"
00072 "BASIC PARAMETERS:\n"
00073 "-----------------\n"
00074 "--imethod\n"
00075 "The interpolation method used for reconstruction.\n"
00076 "\n"
00077 "--detimg\n"
00078 "Specify if the resampled image of the input frame should be generated. There-\n"
00079 "fore all slitlets of all IFUs are aligned one next to the other. This frame\n"
00080 "serves for quality control. One can immediately see if the reconstruction was\n"
00081 "successful.\n"
00082 "\n"
00083 "--file_extension"
00084 "Set this parameter to TRUE if the EXPTIME keyword should be appended to\n"
00085 "the output filenames.\n"
00086 "\n"
00087 "ADVANCED PARAMETERS\n"
00088 "-------------------\n"
00089 "--flux\n"
00090 "Specify if flux conservation should be applied.\n"
00091 "\n"
00092 "--neighborhoodRange\n"
00093 "Defines the range to search for neighbors during reconstruction\n"
00094 "\n"
00095 "--b_samples\n"
00096 "The number of samples in spectral direction for the reconstructed cube. Ideal-\n"
00097 "ly this number should be greater than 2048, the detector size.\n"
00098 "\n"
00099 "--b_start\n"
00100 "--b_end\n"
00101 "Used to define manually the start and end wavelength for the reconstructed\n"
00102 "cube. By default the internally defined values are used.\n"
00103 "\n"
00104 "--file_extension"
00105 "Set to TRUE if OBS_ID (from input frame header) should be appended to the\n"
00106 "output frame.\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 "\n"
00125 "  Output files:\n"
00126 "\n"
00127 "   DO                    KMOS\n"
00128 "   category              Type     Explanation\n"
00129 "   --------              -----    -----------\n"
00130 "   CUBE_DARK   or        F3I      Reconstructed cube   \n"
00131 "   CUBE_FLAT   or        RAW/F2D  with or without noise\n"
00132 "   CUBE_ARC    or                                      \n"
00133 "   CUBE_OBJECT or                                      \n"
00134 "   CUBE_STD    or                                      \n"
00135 "   CUBE_SCIENCE                                        \n"
00136 "-------------------------------------------------------------------------------\n"
00137 "\n";
00138 
00139 /*-----------------------------------------------------------------------------
00140  *                              Functions code
00141  *----------------------------------------------------------------------------*/
00142 
00159 int cpl_plugin_get_info(cpl_pluginlist *list)
00160 {
00161     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00162     cpl_plugin *plugin = &recipe->interface;
00163 
00164     cpl_plugin_init(plugin,
00165                         CPL_PLUGIN_API,
00166                         KMOS_BINARY_VERSION,
00167                         CPL_PLUGIN_TYPE_RECIPE,
00168                         "kmo_reconstruct",
00169                         "Performs the cube reconstruction "
00170                         "using different interpolation methods.",
00171                         kmo_reconstruct_description,
00172                         "Alex Agudo Berbel",
00173                         "agudo@mpe.mpg.de",
00174                         kmos_get_license(),
00175                         kmo_reconstruct_create,
00176                         kmo_reconstruct_exec,
00177                         kmo_reconstruct_destroy);
00178 
00179     cpl_pluginlist_append(list, plugin);
00180 
00181     return 0;
00182 }
00183 
00191 static int kmo_reconstruct_create(cpl_plugin *plugin)
00192 {
00193     cpl_recipe *recipe;
00194     cpl_parameter *p;
00195 
00196     /* Check that the plugin is part of a valid recipe */
00197     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00198         recipe = (cpl_recipe *)plugin;
00199     else
00200         return -1;
00201 
00202     /* Create the parameters list in the cpl_recipe object */
00203     recipe->parameters = cpl_parameterlist_new();
00204 
00205     /* Fill the parameters list */
00206     /* --imethod */
00207     p = cpl_parameter_new_value("kmos.kmo_reconstruct.imethod",
00208                                 CPL_TYPE_STRING,
00209                                 "Method to use for interpolation. "
00210                                 "[\"NN\" (nearest neighbour), "
00211                                 "\"lwNN\" (linear weighted nearest neighbor), "
00212                                 "\"swNN\" (square weighted nearest neighbor), "
00213                                 "\"MS\" (Modified Shepard's method)"
00214                                 "\"CS\" (Cubic spline)]",
00215                                 "kmos.kmo_reconstruct",
00216                                 "CS");
00217     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00218     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00219     cpl_parameterlist_append(recipe->parameters, p);
00220 
00221     /* --neighborhoodRange */
00222     p = cpl_parameter_new_value("kmos.kmo_reconstruct.neighborhoodRange",
00223                                 CPL_TYPE_DOUBLE,
00224                                 "Defines the range to search for neighbors. "
00225                                 "in pixels",
00226                                 "kmos.kmo_reconstruct",
00227                                 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",
00234                                 CPL_TYPE_BOOL,
00235                                 "TRUE: Apply flux conservation. FALSE: otherwise",
00236                                 "kmos.kmo_reconstruct",
00237                                 FALSE);
00238     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00239     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00240     cpl_parameterlist_append(recipe->parameters, p);
00241 
00242     /* --detectorimage */
00243     p = cpl_parameter_new_value("kmos.kmo_reconstruct.detectorimage",
00244                                 CPL_TYPE_BOOL,
00245                                 "TRUE: if resampled detector frame should be "
00246                                 "created, FALSE: otherwise",
00247                                 "kmos.kmo_reconstruct",
00248                                 FALSE);
00249     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detimg");
00250     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00251     cpl_parameterlist_append(recipe->parameters, p);
00252 
00253     /* --file_extension */
00254     p = cpl_parameter_new_value("kmos.kmo_reconstruct.file_extension",
00255                                 CPL_TYPE_BOOL,
00256                                 "TRUE: if OBS_ID keyword should be appended to "
00257                                 "output frames, FALSE: otherwise",
00258                                 "kmos.kmo_reconstruct",
00259                                 FALSE);
00260     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "file_extension");
00261     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00262     cpl_parameterlist_append(recipe->parameters, p);
00263 
00264     /* --pix_scale */
00265     p = cpl_parameter_new_value("kmos.kmo_reconstruct.pix_scale",
00266                                 CPL_TYPE_DOUBLE,
00267                                 "Change the pixel scale [arcsec]. "
00268                                 "Default of 0.2\" results into cubes of 14x14pix, "
00269                                 "a scale of 0.1\" results into cubes of 28x28pix, "
00270                                 "etc.",
00271                                 "kmos.kmo_reconstruct",
00272                                 0.2);
00273     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
00274     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00275     cpl_parameterlist_append(recipe->parameters, p);
00276 
00277     /* --dev_flip */
00278     p = cpl_parameter_new_value("kmos.kmo_reconstruct.dev_flip",
00279                                 CPL_TYPE_BOOL,
00280                                 "INTENDED FOR PIPELINE DEVELOPERS ONLY: "
00281                                 "Set this parameter to TRUE if the wavelengths "
00282                                 "are ascending on the detector from bottom to "
00283                                 "top (only for old simulation data).",
00284                                 "kmos.kmo_reconstruct",
00285                                 FALSE);
00286     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_flip");
00287     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00288     cpl_parameterlist_append(recipe->parameters, p);
00289 
00290     // add parameters for band-definition
00291     kmo_band_pars_create(recipe->parameters,
00292                          "kmos.kmo_reconstruct");
00293 
00294     return 0;
00295 }
00296 
00302 static int kmo_reconstruct_exec(cpl_plugin *plugin)
00303 {
00304     cpl_recipe  *recipe;
00305 
00306     /* Get the recipe out of the plugin */
00307     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00308         recipe = (cpl_recipe *)plugin;
00309     else return -1;
00310 
00311     return kmo_reconstruct(recipe->parameters, recipe->frames);
00312 }
00313 
00319 static int kmo_reconstruct_destroy(cpl_plugin *plugin)
00320 {
00321     cpl_recipe *recipe;
00322 
00323     /* Get the recipe out of the plugin */
00324     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00325         recipe = (cpl_recipe *)plugin;
00326     else return -1 ;
00327 
00328     cpl_parameterlist_delete(recipe->parameters);
00329     return 0 ;
00330 }
00331 
00346 static int kmo_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00347 {
00348     int                 ret_val                 = 0,
00349                         nr_devices              = 0,
00350                         i                       = 0,
00351                         j                       = 0,
00352                         flux                    = FALSE,
00353                         background              = FALSE,
00354                         index                   = 0,
00355                         detectorimage           = 0,
00356                         *bounds                 = NULL,
00357                         ifu_nr                  = 0,
00358                         obs_id                  = 0,
00359                         file_extension          = FALSE,
00360                         dev_flip                = FALSE,
00361                         detImgCube              = FALSE;
00362     float               *pdet_img_data          = NULL,
00363                         *pdet_img_noise         = NULL,
00364                         *slice                  = NULL;
00365     double              neighborhoodRange       = 1.001,
00366                         pix_scale               = 0.0;
00367 
00368     const char          *imethod                = NULL,
00369                         *input_frame_name       = NULL,
00370                         *output_frame_name      = NULL,
00371                         *filter_id              = NULL,
00372                         *filter_id_tmp          = NULL;
00373     char                *keyword                = NULL,
00374                         *filename_cube          = NULL,
00375                         *filename_img           = NULL,
00376 //                        *fn_lut                 = NULL,
00377                         *suffix                 = NULL,
00378                         *obs_suffix             = NULL,
00379                         *my_filter_id           = NULL,
00380                         *extname                = NULL;
00381     cpl_image           *lcal                   = NULL,
00382                         *det_img_data[KMOS_NR_DETECTORS],
00383                         *det_img_noise[KMOS_NR_DETECTORS];
00384     cpl_imagelist       *cube_data              = NULL,
00385                         *cube_noise             = NULL;
00386     cpl_frame           *rec_frame              = NULL,
00387                         *xcal_frame             = NULL,
00388                         *ycal_frame             = NULL,
00389                         *lcal_frame             = NULL;
00390     cpl_propertylist    *main_header           = NULL,
00391                         *sub_header            = NULL,
00392                         *sub_header_orig       = NULL,
00393                         *actual_sub_header     = NULL,
00394                         *tmp_header            = NULL;
00395     cpl_table           *band_table            = NULL;
00396     gridDefinition      gd;
00397     main_fits_desc      desc1,
00398                         desc2;
00399 
00400     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
00401         det_img_data[i] = NULL;
00402         det_img_noise[i] = NULL;
00403     }
00404 
00405     KMO_TRY
00406     {
00407         kmo_init_fits_desc(&desc1);
00408         kmo_init_fits_desc(&desc2);
00409 
00410         // --- check input ---
00411         KMO_TRY_ASSURE((parlist != NULL) &&
00412                        (frameset != NULL),
00413                        CPL_ERROR_NULL_INPUT,
00414                        "Not all input data is provided!");
00415 
00416         KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00417                        (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) ||
00418                        (cpl_frameset_count_tags(frameset, ARC_ON) == 1) ||
00419                        (cpl_frameset_count_tags(frameset, OBJECT) == 1) ||
00420                        (cpl_frameset_count_tags(frameset, STD) == 1) ||
00421                        (cpl_frameset_count_tags(frameset, SCIENCE) == 1),
00422                        CPL_ERROR_NULL_INPUT,
00423                        "A data frame (DARK, FLAT_ON, ARC_ON, OBJECT, STD or SCIENCE) must "
00424                        "be provided!");
00425 
00426         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00427                        CPL_ERROR_FILE_NOT_FOUND,
00428                        "XCAL frame missing in frameset!!");
00429 
00430         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00431                        CPL_ERROR_FILE_NOT_FOUND,
00432                        "YCAL frame missing in frameset!!");
00433 
00434         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00435                        CPL_ERROR_FILE_NOT_FOUND,
00436                        "LCAL frame missing in frameset!!");
00437 
00438         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00439                        CPL_ERROR_FILE_NOT_FOUND,
00440                        "WAVE_BAND frame missing in frameset!!");
00441 
00442         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_reconstruct") == 1,
00443                        CPL_ERROR_ILLEGAL_INPUT,
00444                        "Cannot identify RAW and CALIB frames!");
00445 
00446         // --- get parameters ---
00447         cpl_msg_info("", "--- Parameter setup for kmo_reconstruct ---");
00448 
00449         KMO_TRY_EXIT_IF_NULL(
00450             imethod = kmo_dfs_get_parameter_string(parlist,
00451                                               "kmos.kmo_reconstruct.imethod"));
00452 
00453         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00454                        (strcmp(imethod, "lwNN") == 0) ||
00455                        (strcmp(imethod, "swNN") == 0) ||
00456                        (strcmp(imethod, "MS") == 0) ||
00457                        (strcmp(imethod, "CS") == 0),
00458                        CPL_ERROR_ILLEGAL_INPUT,
00459                        "imethod must be either \"NN\", \"lwNN\", "
00460                        "\"swNN\", \"MS\" or \"CS\"!");
00461 
00462         KMO_TRY_EXIT_IF_ERROR(
00463             kmo_dfs_print_parameter_help(parlist,
00464                                         "kmos.kmo_reconstruct.imethod"));
00465 
00466         flux = kmo_dfs_get_parameter_bool(parlist,
00467                                           "kmos.kmo_reconstruct.flux");
00468 
00469         KMO_TRY_ASSURE((flux == 0) ||
00470                        (flux == 1),
00471                        CPL_ERROR_ILLEGAL_INPUT,
00472                        "flux must be either FALSE or TRUE!");
00473 
00474         KMO_TRY_EXIT_IF_ERROR(
00475             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.flux"));
00476 
00477         detectorimage = kmo_dfs_get_parameter_bool(parlist,
00478                                           "kmos.kmo_reconstruct.detectorimage");
00479 
00480         KMO_TRY_ASSURE((detectorimage == 0) ||
00481                        (detectorimage == 1),
00482                        CPL_ERROR_ILLEGAL_INPUT,
00483                        "detectorimage must be either 0 or 1 !");
00484 
00485         KMO_TRY_EXIT_IF_ERROR(
00486             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.detectorimage"));
00487 
00488         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00489                 "kmos.kmo_reconstruct.neighborhoodRange");
00490         KMO_TRY_CHECK_ERROR_STATE();
00491         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00492                 CPL_ERROR_ILLEGAL_INPUT,
00493                 "neighborhoodRange must be greater than 0.0");
00494         KMO_TRY_EXIT_IF_ERROR(
00495             kmo_dfs_print_parameter_help(parlist,
00496                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00497 
00498         kmo_band_pars_load(parlist, "kmos.kmo_reconstruct");
00499 
00500         file_extension = kmo_dfs_get_parameter_bool(parlist,
00501                                         "kmos.kmo_reconstruct.file_extension");
00502         KMO_TRY_CHECK_ERROR_STATE();
00503         KMO_TRY_EXIT_IF_ERROR(
00504            kmo_dfs_print_parameter_help(parlist,
00505                                        "kmos.kmo_reconstruct.file_extension"));
00506 
00507         pix_scale = kmo_dfs_get_parameter_double(parlist,
00508                                         "kmos.kmo_reconstruct.pix_scale");
00509         KMO_TRY_CHECK_ERROR_STATE();
00510         KMO_TRY_EXIT_IF_ERROR(
00511            kmo_dfs_print_parameter_help(parlist,
00512                                        "kmos.kmo_reconstruct.pix_scale"));
00513         KMO_TRY_ASSURE((pix_scale >= 0.01) &&
00514                        (pix_scale <= 0.4),
00515                        CPL_ERROR_ILLEGAL_INPUT,
00516                        "pix_scale must be between 0.01 and 0.4 (results in cubes "
00517                        "with 7x7 to 280x280 pixels)!");
00518 
00519         dev_flip = kmo_dfs_get_parameter_bool(parlist,
00520                                            "kmos.kmo_reconstruct.dev_flip");
00521         KMO_TRY_CHECK_ERROR_STATE();
00522         KMO_TRY_EXIT_IF_ERROR(
00523             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.dev_flip"));
00524         KMO_TRY_ASSURE((dev_flip == TRUE) ||
00525                        (dev_flip == FALSE),
00526                        CPL_ERROR_ILLEGAL_INPUT,
00527                        "dev_flip must be TRUE or FALSE!");
00528 
00529 
00530         cpl_msg_info("", "-------------------------------------------");
00531 
00532         // load descriptor and header of data frame to reconstruct
00533         if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00534             input_frame_name = DARK;
00535             output_frame_name = CUBE_DARK;
00536         } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
00537             input_frame_name = FLAT_ON;
00538             output_frame_name = CUBE_FLAT;
00539         } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
00540             input_frame_name = ARC_ON;
00541             output_frame_name = CUBE_ARC;
00542         } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
00543             input_frame_name = OBJECT;
00544             output_frame_name = CUBE_OBJECT;
00545         } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
00546             input_frame_name = STD;
00547             output_frame_name = CUBE_STD;
00548         } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
00549             input_frame_name = SCIENCE;
00550             output_frame_name = CUBE_SCIENCE;
00551         }
00552 
00553         // assure that filters, grating and rotation offsets match for
00554         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
00555         // frames)
00556         // check if filter_id and grating_id match for all detectors
00557         KMO_TRY_EXIT_IF_ERROR(
00558             kmo_check_frame_setup(frameset, XCAL, YCAL,
00559                                        TRUE, FALSE, TRUE));
00560         KMO_TRY_EXIT_IF_ERROR(
00561             kmo_check_frame_setup(frameset, XCAL, LCAL,
00562                                        TRUE, FALSE, TRUE));
00563 
00564 // This check doesn't make sense here since OCS.ROT.NAANGLE is compared.
00565 // When creating the calibration files the RAW exposures needn't have been
00566 // provided in the same order
00567 //        KMO_TRY_EXIT_IF_ERROR(
00568 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00569 //        KMO_TRY_EXIT_IF_ERROR(
00570 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00571 
00572         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00573 
00574             // check if filters, gratings and rotator offset match
00575             // (except for DARK frames)
00576             KMO_TRY_EXIT_IF_ERROR(
00577                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00578                                            TRUE, FALSE, FALSE));
00579 /*
00580             // check if rotator offset don't differ to much
00581             cpl_frame        *f1 = NULL, *f2 = NULL;
00582             cpl_propertylist *h1 = NULL, *h2 = NULL;
00583             char             *kw = NULL;
00584             double           tmp_dbl1 = 0.0, tmp_dbl2 = 0.0;
00585 
00586             KMO_TRY_EXIT_IF_NULL(
00587                 f1 = kmo_dfs_get_frame(frameset, XCAL));
00588 
00589             KMO_TRY_EXIT_IF_NULL(
00590                 f2 = kmo_dfs_get_frame(frameset, input_frame_name));
00591             h1 = kmclipm_propertylist_load(cpl_frame_get_filename(f1), 0);
00592             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00593                 cpl_msg_error("","File not found: %s!",
00594                               cpl_frame_get_filename(f1));
00595                 KMO_TRY_CHECK_ERROR_STATE();
00596             }
00597 
00598             h2 = kmclipm_propertylist_load(cpl_frame_get_filename(f2), 0);
00599             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00600                 cpl_msg_error("","File not found: %s!",
00601                               cpl_frame_get_filename(f2));
00602                 KMO_TRY_CHECK_ERROR_STATE();
00603             }
00604             KMO_TRY_EXIT_IF_NULL(
00605                 kw = cpl_sprintf("%s", ROTANGLE));
00606             tmp_dbl1 = cpl_propertylist_get_double(h1, kw);
00607             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00608                 KMO_TRY_ASSURE(1 == 0,
00609                                CPL_ERROR_ILLEGAL_INPUT,
00610                                "keyword \n%s\n of frame %s is missing!",
00611                                keyword, XCAL);
00612             }
00613 
00614             tmp_dbl2 = cpl_propertylist_get_double(h2, kw);
00615             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00616                 KMO_TRY_ASSURE(1 == 0,
00617                                CPL_ERROR_ILLEGAL_INPUT,
00618                                "keyword \n%s\n of frame %s is missing!",
00619                                keyword, input_frame_name);
00620             }
00621 
00622             // strip angles below 0 deg and above 360 deg
00623             kmclipm_strip_angle(&tmp_dbl1);
00624             kmclipm_strip_angle(&tmp_dbl2);
00625 
00626             if (fabs(tmp_dbl1 - tmp_dbl2) > 30.) {
00627                 if ((fabs(tmp_dbl1) < 0.001) && (tmp_dbl2>330) && (tmp_dbl2<360)) {
00628                     // singularity!
00629                     // we have rot=0 for XCAL and rot>330 | rot<360 for input frame
00630                 } else {
00631                 cpl_msg_warning("","The angle of the calibration files (%g deg) "
00632                                 "and the angle of the frame to reconstruct"
00633                                 " (%g deg) differ by %g deg! Think about using "
00634                                 "calibration files matching better the actual "
00635                                 "rotator offset (ESO OCS ROT NAANGLE)",
00636                                 tmp_dbl1, tmp_dbl2,
00637                                 fabs(tmp_dbl1 - tmp_dbl2));
00638                 }
00639             }
00640 
00641             cpl_propertylist_delete(h1); h1 = NULL;
00642             cpl_propertylist_delete(h2); h2 = NULL;
00643             cpl_free(kw); kw = NULL;
00644 */
00645         }
00646 
00647         KMO_TRY_EXIT_IF_NULL(
00648             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00649         KMO_TRY_EXIT_IF_NULL(
00650             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00651         KMO_TRY_EXIT_IF_NULL(
00652             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00653 
00654         KMO_TRY_EXIT_IF_ERROR(
00655             kmo_check_frame_setup_md5_xycal(frameset));
00656         KMO_TRY_EXIT_IF_ERROR(
00657             kmo_check_frame_setup_md5(frameset));
00658 
00659         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00660         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00661         cpl_msg_info("", "-------------------------------------------");
00662 
00663 
00664         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00665         KMO_TRY_CHECK_ERROR_STATE();
00666 
00667         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00668                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00669                        (desc1.ex_badpix == FALSE) &&
00670                        ((desc1.fits_type == raw_fits) ||
00671                         (desc1.fits_type == f2d_fits)) &&
00672                        (desc1.frame_type == detector_frame),
00673                        CPL_ERROR_ILLEGAL_INPUT,
00674                        "The frame to reconstruct isn't in the correct format!!!"
00675                        "Exactly 3 frames, or 6 with noise are expected!");
00676 
00677         if (!desc1.ex_noise) {
00678             nr_devices = desc1.nr_ext;
00679         } else {
00680             nr_devices = desc1.nr_ext / 2;
00681         }
00682 
00683         // compare descriptor of XCAL and data frame to reconstruct
00684         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00685         KMO_TRY_CHECK_ERROR_STATE();
00686 
00687         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00688                        (desc1.ex_badpix == desc2.ex_badpix) &&
00689                        (desc1.frame_type == desc2.frame_type),
00690                        CPL_ERROR_ILLEGAL_INPUT,
00691                        "XCAL isn't in the correct format!!!");
00692 
00693         kmo_free_fits_desc(&desc2);
00694 
00695         // compare descriptor of YCAL and data frame to reconstruct
00696         kmo_init_fits_desc(&desc2);
00697 
00698         KMO_TRY_EXIT_IF_NULL(
00699             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00700 
00701         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_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                        "YCAL isn't in the correct format!!!");
00709 
00710         kmo_free_fits_desc(&desc2);
00711 
00712         // compare descriptor of LCAL and data frame to reconstruct
00713         kmo_init_fits_desc(&desc2);
00714 
00715         KMO_TRY_EXIT_IF_NULL(
00716             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00717 
00718         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_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                        "LCAL isn't in the correct format!!!");
00726 
00727         kmo_free_fits_desc(&desc2);
00728 
00729         //
00730         // --- load, update & save primary header ---
00731         //
00732         KMO_TRY_EXIT_IF_NULL(
00733             main_header = kmo_dfs_load_primary_header(frameset,
00734                                                       input_frame_name));
00735 
00736         KMO_TRY_EXIT_IF_NULL(
00737             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00738 
00739         // assert that filters have correct IDs and that all detectors of all
00740         // input frames have the same filter set
00741         for (i = 1; i <= nr_devices; i++) {
00742             // ESO INS FILTi ID
00743             KMO_TRY_EXIT_IF_NULL(
00744                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00745                                       IFU_FILTID_POSTFIX));
00746 
00747             KMO_TRY_EXIT_IF_NULL(
00748                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00749 
00750             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00751                            (strcmp(filter_id, "YJ") == 0) ||
00752                            (strcmp(filter_id, "H") == 0) ||
00753                            (strcmp(filter_id, "K") == 0) ||
00754                            (strcmp(filter_id, "HK") == 0),
00755                            CPL_ERROR_ILLEGAL_INPUT,
00756                            "Filter ID in primary header of LCAL frame must "
00757                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00758                            "\"HK\" !");
00759 
00760             if (strcmp(input_frame_name, DARK) != 0) {
00761                 // dark needn't to be taken with filter!
00762 
00763                 KMO_TRY_EXIT_IF_NULL(
00764                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00765                                                                 keyword));
00766                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00767                                CPL_ERROR_ILLEGAL_INPUT,
00768                                "Filter IDs must be the same for LCAL frame and "
00769                                "the frame to reconstruct!"
00770                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00771                                i, filter_id, input_frame_name, filter_id_tmp);
00772             }
00773             cpl_free(keyword); keyword = NULL;
00774         }
00775         KMO_TRY_EXIT_IF_NULL(
00776             my_filter_id = cpl_strdup(filter_id));
00777         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00778 
00779         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00780         KMO_TRY_CHECK_ERROR_STATE();
00781 
00782         KMO_TRY_EXIT_IF_NULL(
00783             filename_cube = cpl_sprintf("%s", output_frame_name));
00784         KMO_TRY_EXIT_IF_NULL(
00785             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00786         if (file_extension) {
00787             KMO_TRY_EXIT_IF_NULL(
00788                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00789         } else {
00790             KMO_TRY_EXIT_IF_NULL(
00791                 obs_suffix = cpl_sprintf("%s", ""));
00792         }
00793 
00794         KMO_TRY_EXIT_IF_ERROR(
00795             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00796                                      rec_frame, NULL, parlist, cpl_func));
00797 
00798         // setup grid definition, wavelength start and end points will be set
00799         // in the detector loop
00800         KMO_TRY_EXIT_IF_ERROR(
00801             kmclipm_setup_grid(&gd, imethod, neighborhoodRange));
00802 
00803 
00804         // adapt pixel range if desired
00805         if (fabs(pix_scale*1000-KMOS_PIXEL_RESOLUTION) > 0.001) {
00806             int     pixNewX =   0,
00807                     pixNewY =   0;
00808             double  deltaNewX = 0.,
00809                     deltaNewY = 0.;
00810 
00811             pix_scale *=1000;
00812 
00813             // calculate temporary (eventually fractional) pixel scale
00814             double pixNewTmp = KMOS_SLITLET_X*KMOS_PIXEL_RESOLUTION/pix_scale;
00815             deltaNewX = KMOS_SLITLET_X*KMOS_PIXEL_RESOLUTION/pixNewTmp;
00816 
00817             // calculate integer pixel scale
00818             pixNewX = floor(pixNewTmp+.5);
00819             deltaNewX = 14*200/pixNewX;
00820 
00821             // calculate final pixel scale in x and y
00822             pixNewX = floor(KMOS_SLITLET_X*KMOS_PIXEL_RESOLUTION/pix_scale+.5);
00823             pixNewY = floor(KMOS_SLITLET_Y*KMOS_PIXEL_RESOLUTION/pix_scale+.5);
00824             deltaNewX = KMOS_SLITLET_X*KMOS_PIXEL_RESOLUTION/pixNewX;
00825             deltaNewY = KMOS_SLITLET_Y*KMOS_PIXEL_RESOLUTION/pixNewY;
00826 
00827             cpl_msg_info("", "Pixel resolution has been changed from 0.2\" to %g\"", deltaNewX/1000);
00828             if (fabs(pixNewTmp-pixNewX) > 0.0001) {
00829                 cpl_msg_info("", "(%g\" would have resulted in cubes with %g pixels...)", pix_scale/1000, pixNewTmp);
00830             }
00831             cpl_msg_info("", "   Created cubes will have %dx%d pixels, instead the standard 14x14 pixels", pixNewX, pixNewY);
00832 
00833             gd.x.delta = deltaNewX;
00834             gd.y.delta = deltaNewY;
00835             gd.x.dim = pixNewX;
00836             gd.y.dim = pixNewY;
00837         }
00838 
00839         KMO_TRY_EXIT_IF_NULL(
00840             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00841 
00842         KMO_TRY_EXIT_IF_NULL(
00843             bounds = kmclipm_extract_bounds(tmp_header));
00844         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00845 
00846         if (detectorimage == TRUE) {
00847             KMO_TRY_EXIT_IF_ERROR(
00848                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00849                                          rec_frame, NULL, parlist, cpl_func));
00850         }
00851 
00852         /* loop through all detectors */
00853         for (i = 1; i <= nr_devices; i++) {
00854             cpl_msg_info("","Processing detector No. %d", i);
00855 
00856             // load lcal
00857             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00858             // doesn't differ too much with different ROTANGLEs.
00859             double rotangle_found;
00860             KMO_TRY_EXIT_IF_NULL(
00861                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00862                                               FALSE, NULL, &rotangle_found));
00863 
00864             char *tmp_band_method = getenv("KMO_BAND_METHOD");
00865             int band_method = 0;
00866             if (tmp_band_method != NULL) {
00867                 band_method = atoi(tmp_band_method);
00868             }
00869 
00870             KMO_TRY_EXIT_IF_NULL(
00871                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00872 
00873             KMO_TRY_EXIT_IF_ERROR(
00874                 kmclipm_setup_grid_band_lcal(&gd, lcal, my_filter_id,
00875                                              band_method, band_table));
00876             cpl_table_delete(band_table); band_table = NULL;
00877 
00878             cpl_image_delete(lcal); lcal = NULL;
00879 
00880             if (detectorimage == TRUE) {
00881                 KMO_TRY_EXIT_IF_NULL(
00882                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00883                                                       gd.l.dim, CPL_TYPE_FLOAT));
00884                 KMO_TRY_EXIT_IF_NULL(
00885                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00886 
00887                 KMO_TRY_EXIT_IF_NULL(
00888                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00889                                                       gd.l.dim, CPL_TYPE_FLOAT));
00890                 KMO_TRY_EXIT_IF_NULL(
00891                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00892             }
00893 
00894 
00895             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00896                 /* update sub-header */
00897                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00898 
00899                 /* load raw image and sub-header*/
00900                 KMO_TRY_EXIT_IF_NULL(
00901                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00902                                                          i, FALSE));
00903                 KMO_TRY_EXIT_IF_NULL(
00904                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00905 
00906                 // check if IFU is valid according to main header keywords &
00907                 // calibration files
00908 
00909                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00910                     KMO_TRY_EXIT_IF_NULL(
00911                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00912                                               IFU_VALID_POSTFIX));
00913                     KMO_TRY_CHECK_ERROR_STATE();
00914                     cpl_propertylist_get_string(main_header, keyword);
00915                     cpl_free(keyword); keyword = NULL;
00916                 } else {
00917                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00918                     // reconstructed
00919                     cpl_propertylist_get_string(main_header, "ggg");
00920                 }
00921 
00922                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00923                     (bounds[2*(ifu_nr-1)] != -1) &&
00924                     (bounds[2*(ifu_nr-1)+1] != -1))
00925                 {
00926                     cpl_error_reset();
00927                     // IFU is valid
00928                     actual_sub_header = sub_header;
00929 
00930                     // calculate WCS
00931                     KMO_TRY_EXIT_IF_ERROR(
00932                         kmo_calc_wcs(main_header, actual_sub_header, ifu_nr,
00933                                      gd.l.start, gd.l.delta));
00934 
00935                     // reconstruct data and noise (if available)
00936                     if (j == 0) {
00937                         sat_mode_msg = FALSE;
00938                     } else {
00939                         sat_mode_msg = TRUE;
00940                     }
00941                     KMO_TRY_EXIT_IF_ERROR(
00942                         kmo_reconstruct_sci(ifu_nr,
00943                                             bounds[2*(ifu_nr-1)],
00944                                             bounds[2*(ifu_nr-1)+1],
00945                                             rec_frame,
00946                                             input_frame_name,
00947                                             NULL,
00948                                             NULL,
00949                                             NULL,
00950                                             xcal_frame,
00951                                             ycal_frame,
00952                                             lcal_frame,
00953                                             &gd,
00954                                             &cube_data,
00955                                             &cube_noise,
00956                                             flux,
00957                                             background));
00958                 } else {
00959                     // IFU is invalid
00960                     actual_sub_header = sub_header_orig;
00961                     cpl_error_reset();
00962                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
00963 
00964                 if (detectorimage) {
00965                     if (cube_data != NULL) {
00966                         for (int l=0; l<gd.l.dim; l++) {
00967                             KMO_TRY_EXIT_IF_NULL(
00968                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
00969                             for (int y=0; y<gd.y.dim; y++) {
00970                                 for (int x=0; x<gd.x.dim; x++) {
00971                                     int ix = x +
00972                                              y * gd.x.dim +
00973                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00974                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00975                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
00976                                 }
00977                             }
00978                         }
00979                     }
00980                     if (cube_noise != NULL) {
00981                         if (detectorimage) {
00982                             detImgCube = TRUE;
00983                         }
00984                         for (int l=0; l<gd.l.dim; l++) {
00985                             KMO_TRY_EXIT_IF_NULL(
00986                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
00987                             for (int y=0; y<gd.y.dim; y++) {
00988                                 for (int x=0; x<gd.x.dim; x++) {
00989                                     int ix = x +
00990                                              y * gd.x.dim +
00991                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00992                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00993                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
00994                                 }
00995                             }
00996                         }
00997                     }
00998                 }
00999 
01000                 // save output
01001                 KMO_TRY_EXIT_IF_NULL(
01002                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
01003                                                   EXT_DATA));
01004 
01005                 KMO_TRY_EXIT_IF_ERROR(
01006                     kmclipm_update_property_string(actual_sub_header,
01007                                             EXTNAME,
01008                                             extname,
01009                                             "FITS extension name"));
01010 
01011                 cpl_free(extname); extname = NULL;
01012 
01013                 KMO_TRY_EXIT_IF_ERROR(
01014                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
01015                                       actual_sub_header, 0./0.));
01016 
01017                 if (cube_noise != NULL) {
01018                     KMO_TRY_EXIT_IF_NULL(
01019                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01020                                                       EXT_NOISE));
01021 
01022                     KMO_TRY_EXIT_IF_ERROR(
01023                         kmclipm_update_property_string(actual_sub_header,
01024                                                 EXTNAME,
01025                                                 extname,
01026                                                 "FITS extension name"));
01027 
01028                     cpl_free(extname); extname = NULL;
01029 
01030                     KMO_TRY_EXIT_IF_ERROR(
01031                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
01032                                           actual_sub_header, 0./0.));
01033                 }
01034 
01035                 cpl_imagelist_delete(cube_data); cube_data = NULL;
01036                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01037                 cpl_propertylist_delete(sub_header); sub_header = NULL;
01038                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01039             } // for j IFUs
01040 
01041             if (detectorimage) {
01042                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01043                                            i, FALSE);
01044                 KMO_TRY_CHECK_ERROR_STATE();
01045 
01046                 KMO_TRY_EXIT_IF_NULL(
01047                     tmp_header = kmclipm_propertylist_load(
01048                                          cpl_frame_get_filename(rec_frame), index));
01049                 KMO_TRY_EXIT_IF_ERROR(
01050                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
01051                                          obs_suffix, tmp_header, dev_flip, FALSE));
01052                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01053 
01054                 if (detImgCube) {
01055                     if (desc1.ex_noise) {
01056                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
01057                                                    i, TRUE);
01058                         KMO_TRY_CHECK_ERROR_STATE();
01059                     } else {
01060                         // use same index as for data frame, since input frame
01061                         // has just 3 extensions
01062                     }
01063                     KMO_TRY_EXIT_IF_NULL(
01064                         tmp_header = kmclipm_propertylist_load(
01065                                              cpl_frame_get_filename(rec_frame), index));
01066                     KMO_TRY_EXIT_IF_ERROR(
01067                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01068                                              obs_suffix, tmp_header, dev_flip, TRUE));
01069                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01070                 }
01071             }
01072 
01073             // free memory
01074             cpl_imagelist_delete(cube_data); cube_data = NULL;
01075             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01076             cpl_propertylist_delete(sub_header); sub_header = NULL;
01077             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01078         } // for i devices
01079     }
01080     KMO_CATCH
01081     {
01082         KMO_CATCH_MSG();
01083         ret_val = -1;
01084     }
01085 
01086     kmo_free_fits_desc(&desc1);
01087     kmo_free_fits_desc(&desc2);
01088     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
01089         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01090         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01091     }
01092     cpl_free(my_filter_id); my_filter_id = NULL;
01093     cpl_free(bounds); bounds = NULL;
01094     cpl_propertylist_delete(main_header); main_header = NULL;
01095     cpl_propertylist_delete(sub_header); sub_header = NULL;
01096     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01097     cpl_imagelist_delete(cube_data); cube_data = NULL;
01098     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01099     cpl_free(obs_suffix); obs_suffix = NULL;
01100     cpl_free(suffix); suffix = NULL;
01101     cpl_free(filename_img); filename_img = NULL;
01102     cpl_free(filename_cube); filename_cube = NULL;
01103     sat_mode_msg = FALSE;
01104 
01105     return ret_val;
01106 }
01107