KMOS Pipeline Reference Manual  1.0.7
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.36 2013/01/23 08:12:01 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/01/23 08:12:01 $
00024  * $Revision: 1.36 $
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 "ADVANCED PARAMETERS\n"
00084 "-------------------\n"
00085 "--flux\n"
00086 "Specify if flux conservation should be applied.\n"
00087 "\n"
00088 "--neighborhoodRange\n"
00089 "Defines the range to search for neighbors during reconstruction\n"
00090 "\n"
00091 "--b_samples\n"
00092 "The number of samples in spectral direction for the reconstructed cube. Ideal-\n"
00093 "ly this number should be greater than 2048, the detector size.\n"
00094 "\n"
00095 "--b_start\n"
00096 "--b_end\n"
00097 "Used to define manually the start and end wavelength for the reconstructed\n"
00098 "cube. By default the internally defined values are used.\n"
00099 "\n"
00100 "--outputextension"
00101 "Set to TRUE if OBS_ID (from input frame header) should be appended to the\n"
00102 "output frame.\n"
00103 "\n"
00104 "-------------------------------------------------------------------------------\n"
00105 "  Input files:\n"
00106 "\n"
00107 "   DO                  KMOS                                                    \n"
00108 "   category            Type     Explanation                    Required #Frames\n"
00109 "   --------            -----    -----------                    -------- -------\n"
00110 "   DARK    or          RAW/F2D  data with                          Y       1   \n"
00111 "   FLAT_ON or          RAW/F2D  or without noise                               \n"
00112 "   ARC_ON  or          RAW/F2D                                                 \n"
00113 "   OBJECT  or          RAW                                                     \n"
00114 "   STD     or          RAW                                                     \n"
00115 "   SCIENCE             RAW                                                     \n"
00116 "   XCAL                F2D      x-direction calib. frame           Y       1   \n"
00117 "   YCAL                F2D      y-direction calib. frame           Y       1   \n"
00118 "   LCAL                F2D      Wavelength calib. frame            Y       1   \n"
00119 "   WAVE_BAND           F2L      Table with start-/end-wavelengths  Y       1   \n"
00120 "\n"
00121 "  Output files:\n"
00122 "\n"
00123 "   DO                    KMOS\n"
00124 "   category              Type     Explanation\n"
00125 "   --------              -----    -----------\n"
00126 "   CUBE_DARK   or        F3I      Reconstructed cube   \n"
00127 "   CUBE_FLAT   or        RAW/F2D  with or without noise\n"
00128 "   CUBE_ARC    or                                      \n"
00129 "   CUBE_OBJECT or                                      \n"
00130 "   CUBE_STD    or                                      \n"
00131 "   CUBE_SCIENCE                                        \n"
00132 "-------------------------------------------------------------------------------\n"
00133 "\n";
00134 
00135 /*-----------------------------------------------------------------------------
00136  *                              Functions code
00137  *----------------------------------------------------------------------------*/
00138 
00155 int cpl_plugin_get_info(cpl_pluginlist *list)
00156 {
00157     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00158     cpl_plugin *plugin = &recipe->interface;
00159 
00160     cpl_plugin_init(plugin,
00161                         CPL_PLUGIN_API,
00162                         KMOS_BINARY_VERSION,
00163                         CPL_PLUGIN_TYPE_RECIPE,
00164                         "kmo_reconstruct",
00165                         "Performs the cube reconstruction "
00166                         "using different interpolation methods.",
00167                         kmo_reconstruct_description,
00168                         "Alex Agudo Berbel",
00169                         "agudo@mpe.mpg.de",
00170                         kmos_get_license(),
00171                         kmo_reconstruct_create,
00172                         kmo_reconstruct_exec,
00173                         kmo_reconstruct_destroy);
00174 
00175     cpl_pluginlist_append(list, plugin);
00176 
00177     return 0;
00178 }
00179 
00187 static int kmo_reconstruct_create(cpl_plugin *plugin)
00188 {
00189     cpl_recipe *recipe;
00190     cpl_parameter *p;
00191 
00192     /* Check that the plugin is part of a valid recipe */
00193     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00194         recipe = (cpl_recipe *)plugin;
00195     else
00196         return -1;
00197 
00198     /* Create the parameters list in the cpl_recipe object */
00199     recipe->parameters = cpl_parameterlist_new();
00200 
00201     /* Fill the parameters list */
00202     /* --imethod */
00203     p = cpl_parameter_new_value("kmos.kmo_reconstruct.imethod",
00204                                 CPL_TYPE_STRING,
00205                                 "Method to use for interpolation. "
00206                                 "[\"NN\" (nearest neighbour), "
00207                                 "\"lwNN\" (linear weighted nearest neighbor), "
00208                                 "\"swNN\" (square weighted nearest neighbor), "
00209                                 "\"MS\" (Modified Shepard's method)"
00210                                 "\"CS\" (Cubic spline)]",
00211                                 "kmos.kmo_reconstruct",
00212                                 "CS");
00213     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00214     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00215     cpl_parameterlist_append(recipe->parameters, p);
00216 
00217     /* --neighborhoodRange */
00218     p = cpl_parameter_new_value("kmos.kmo_reconstruct.neighborhoodRange",
00219                                 CPL_TYPE_DOUBLE,
00220                                 "Defines the range to search for neighbors. "
00221                                 "in pixels",
00222                                 "kmos.kmo_reconstruct",
00223                                 1.001);
00224     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00225     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00226     cpl_parameterlist_append(recipe->parameters, p);
00227 
00228     /* --flux */
00229     p = cpl_parameter_new_value("kmos.kmo_reconstruct.flux",
00230                                 CPL_TYPE_BOOL,
00231                                 "TRUE: Apply flux conservation. FALSE: otherwise",
00232                                 "kmos.kmo_reconstruct",
00233                                 FALSE);
00234     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00235     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00236     cpl_parameterlist_append(recipe->parameters, p);
00237 
00238     /* --detectorimage */
00239     p = cpl_parameter_new_value("kmos.kmo_reconstruct.detectorimage",
00240                                 CPL_TYPE_BOOL,
00241                                 "TRUE: if resampled detector frame should be "
00242                                 "created, FALSE: otherwise",
00243                                 "kmos.kmo_reconstruct",
00244                                 FALSE);
00245     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detimg");
00246     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00247     cpl_parameterlist_append(recipe->parameters, p);
00248 
00249     /* --outputextension */
00250     p = cpl_parameter_new_value("kmos.kmo_reconstruct.outputextension",
00251                                 CPL_TYPE_BOOL,
00252                                 "TRUE: if OBS_ID keyword should be appended to "
00253                                 "output frames, FALSE: otherwise",
00254                                 "kmos.kmo_reconstruct",
00255                                 FALSE);
00256     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "outputextension");
00257     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00258     cpl_parameterlist_append(recipe->parameters, p);
00259 
00260     /* --dev_flip */
00261     p = cpl_parameter_new_value("kmos.kmo_reconstruct.dev_flip",
00262                                 CPL_TYPE_BOOL,
00263                                 "INTENDED FOR PIPELINE DEVELOPERS ONLY: "
00264                                 "Set this parameter to TRUE if the wavelengths "
00265                                 "are ascending on the detector from bottom to "
00266                                 "top (only for old simulation data).",
00267                                 "kmos.kmo_reconstruct",
00268                                 FALSE);
00269     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_flip");
00270     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00271     cpl_parameterlist_append(recipe->parameters, p);
00272 
00273     // add parameters for band-definition
00274     kmo_band_pars_create(recipe->parameters,
00275                          "kmos.kmo_reconstruct");
00276 
00277     return 0;
00278 }
00279 
00285 static int kmo_reconstruct_exec(cpl_plugin *plugin)
00286 {
00287     cpl_recipe  *recipe;
00288 
00289     /* Get the recipe out of the plugin */
00290     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00291         recipe = (cpl_recipe *)plugin;
00292     else return -1;
00293 
00294     return kmo_reconstruct(recipe->parameters, recipe->frames);
00295 }
00296 
00302 static int kmo_reconstruct_destroy(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     cpl_parameterlist_delete(recipe->parameters);
00312     return 0 ;
00313 }
00314 
00329 static int kmo_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00330 {
00331     int                 ret_val                 = 0,
00332                         nr_devices              = 0,
00333                         i                       = 0,
00334                         j                       = 0,
00335                         flux                    = 0,
00336                         index                   = 0,
00337                         detectorimage           = 0,
00338                         *bounds                 = NULL,
00339                         ifu_nr                  = 0,
00340                         obs_id                  = 0,
00341                         outputextension         = FALSE,
00342                         dev_flip                = FALSE,
00343                         detImgCube              = FALSE;
00344     float               *pdet_img_data          = NULL,
00345                         *pdet_img_noise         = NULL,
00346                         *slice                  = NULL;
00347     double              neighborhoodRange       = 1.001;
00348 
00349     const char          *imethod                = NULL,
00350                         *input_frame_name       = NULL,
00351                         *output_frame_name      = NULL,
00352                         *filter_id              = NULL,
00353                         *filter_id_tmp          = NULL;
00354     char                *keyword                = NULL,
00355                         *filename_cube          = NULL,
00356                         *filename_img           = NULL,
00357 //                        *fn_lut                 = NULL,
00358                         *suffix                 = NULL,
00359                         *obs_suffix             = NULL,
00360                         *my_filter_id           = NULL,
00361                         *extname                = NULL;
00362     cpl_image           *lcal                   = NULL,
00363                         *det_img_data[KMOS_NR_DETECTORS],
00364                         *det_img_noise[KMOS_NR_DETECTORS];
00365     cpl_imagelist       *cube_data              = NULL,
00366                         *cube_noise             = NULL;
00367     cpl_frame           *rec_frame              = NULL,
00368                         *xcal_frame             = NULL,
00369                         *ycal_frame             = NULL,
00370                         *lcal_frame             = NULL;
00371     cpl_propertylist    *main_header           = NULL,
00372                         *sub_header            = NULL,
00373                         *sub_header_orig       = NULL,
00374                         *actual_sub_header     = NULL,
00375                         *tmp_header            = NULL;
00376     cpl_table           *band_table            = NULL;
00377     gridDefinition      gd;
00378     main_fits_desc      desc1,
00379                         desc2;
00380 
00381     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
00382         det_img_data[i] = NULL;
00383         det_img_noise[i] = NULL;
00384     }
00385 
00386     KMO_TRY
00387     {
00388         kmo_init_fits_desc(&desc1);
00389         kmo_init_fits_desc(&desc2);
00390 
00391         // --- check input ---
00392         KMO_TRY_ASSURE((parlist != NULL) &&
00393                        (frameset != NULL),
00394                        CPL_ERROR_NULL_INPUT,
00395                        "Not all input data is provided!");
00396 
00397         KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00398                        (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) ||
00399                        (cpl_frameset_count_tags(frameset, ARC_ON) == 1) ||
00400                        (cpl_frameset_count_tags(frameset, OBJECT) == 1) ||
00401                        (cpl_frameset_count_tags(frameset, STD) == 1) ||
00402                        (cpl_frameset_count_tags(frameset, SCIENCE) == 1),
00403                        CPL_ERROR_NULL_INPUT,
00404                        "A data frame (DARK, FLAT_ON, ARC_ON, OBJECT, STD or SCIENCE) must "
00405                        "be provided!");
00406 
00407         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00408                        CPL_ERROR_FILE_NOT_FOUND,
00409                        "XCAL frame missing in frameset!!");
00410 
00411         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00412                        CPL_ERROR_FILE_NOT_FOUND,
00413                        "YCAL frame missing in frameset!!");
00414 
00415         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00416                        CPL_ERROR_FILE_NOT_FOUND,
00417                        "LCAL frame missing in frameset!!");
00418 
00419         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00420                        CPL_ERROR_FILE_NOT_FOUND,
00421                        "WAVE_BAND frame missing in frameset!!");
00422 
00423         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_reconstruct") == 1,
00424                        CPL_ERROR_ILLEGAL_INPUT,
00425                        "Cannot identify RAW and CALIB frames!");
00426 
00427         // --- get parameters ---
00428         cpl_msg_info("", "--- Parameter setup for kmo_reconstruct ---");
00429 
00430         KMO_TRY_EXIT_IF_NULL(
00431             imethod = kmo_dfs_get_parameter_string(parlist,
00432                                               "kmos.kmo_reconstruct.imethod"));
00433 
00434         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00435                        (strcmp(imethod, "lwNN") == 0) ||
00436                        (strcmp(imethod, "swNN") == 0) ||
00437                        (strcmp(imethod, "MS") == 0) ||
00438                        (strcmp(imethod, "CS") == 0),
00439                        CPL_ERROR_ILLEGAL_INPUT,
00440                        "imethod must be either \"NN\", \"lwNN\", "
00441                        "\"swNN\", \"MS\" or \"CS\"!");
00442 
00443         KMO_TRY_EXIT_IF_ERROR(
00444             kmo_dfs_print_parameter_help(parlist,
00445                                         "kmos.kmo_reconstruct.imethod"));
00446 
00447         flux = kmo_dfs_get_parameter_bool(parlist,
00448                                           "kmos.kmo_reconstruct.flux");
00449 
00450         KMO_TRY_ASSURE((flux == 0) ||
00451                        (flux == 1),
00452                        CPL_ERROR_ILLEGAL_INPUT,
00453                        "flux must be either FALSE or TRUE!");
00454 
00455         KMO_TRY_EXIT_IF_ERROR(
00456             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.flux"));
00457 
00458         detectorimage = kmo_dfs_get_parameter_bool(parlist,
00459                                           "kmos.kmo_reconstruct.detectorimage");
00460 
00461         KMO_TRY_ASSURE((detectorimage == 0) ||
00462                        (detectorimage == 1),
00463                        CPL_ERROR_ILLEGAL_INPUT,
00464                        "detectorimage must be either 0 or 1 !");
00465 
00466         KMO_TRY_EXIT_IF_ERROR(
00467             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.detectorimage"));
00468 
00469         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00470                 "kmos.kmo_reconstruct.neighborhoodRange");
00471         KMO_TRY_CHECK_ERROR_STATE();
00472 
00473         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00474                 CPL_ERROR_ILLEGAL_INPUT,
00475                 "neighborhoodRange must be greater than 0.0");
00476 
00477         KMO_TRY_EXIT_IF_ERROR(
00478             kmo_dfs_print_parameter_help(parlist,
00479                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00480 
00481         kmo_band_pars_load(parlist, "kmos.kmo_reconstruct");
00482 
00483         outputextension = kmo_dfs_get_parameter_bool(parlist,
00484                                         "kmos.kmo_reconstruct.outputextension");
00485         KMO_TRY_CHECK_ERROR_STATE();
00486 
00487         KMO_TRY_EXIT_IF_ERROR(
00488            kmo_dfs_print_parameter_help(parlist,
00489                                        "kmos.kmo_reconstruct.outputextension"));
00490 
00491         dev_flip = kmo_dfs_get_parameter_bool(parlist,
00492                                            "kmos.kmo_reconstruct.dev_flip");
00493         KMO_TRY_CHECK_ERROR_STATE();
00494         KMO_TRY_EXIT_IF_ERROR(
00495             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.dev_flip"));
00496         KMO_TRY_ASSURE((dev_flip == TRUE) ||
00497                        (dev_flip == FALSE),
00498                        CPL_ERROR_ILLEGAL_INPUT,
00499                        "dev_flip must be TRUE or FALSE!");
00500 
00501 
00502         cpl_msg_info("", "-------------------------------------------");
00503 
00504         // load descriptor and header of data frame to reconstruct
00505         if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00506             input_frame_name = DARK;
00507             output_frame_name = CUBE_DARK;
00508         } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
00509             input_frame_name = FLAT_ON;
00510             output_frame_name = CUBE_FLAT;
00511         } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
00512             input_frame_name = ARC_ON;
00513             output_frame_name = CUBE_ARC;
00514         } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
00515             input_frame_name = OBJECT;
00516             output_frame_name = CUBE_OBJECT;
00517         } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
00518             input_frame_name = STD;
00519             output_frame_name = CUBE_STD;
00520         } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
00521             input_frame_name = SCIENCE;
00522             output_frame_name = CUBE_SCIENCE;
00523         }
00524 
00525         // assure that filters, grating and rotation offsets match for
00526         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
00527         // frames)
00528         // check if filter_id and grating_id match for all detectors
00529         KMO_TRY_EXIT_IF_ERROR(
00530             kmo_check_frame_setup(frameset, XCAL, YCAL,
00531                                        TRUE, FALSE, TRUE));
00532         KMO_TRY_EXIT_IF_ERROR(
00533             kmo_check_frame_setup(frameset, XCAL, LCAL,
00534                                        TRUE, FALSE, TRUE));
00535 
00536 // This check doesn't make sense here since OCS.ROT.NAANGLE is compared.
00537 // When creating the calibration files the RAW exposures needn't have been
00538 // provided in the same order
00539 //        KMO_TRY_EXIT_IF_ERROR(
00540 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00541 //        KMO_TRY_EXIT_IF_ERROR(
00542 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00543 
00544         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00545 
00546             // check if filters, gratings and rotator offset match
00547             // (except for DARK frames)
00548             KMO_TRY_EXIT_IF_ERROR(
00549                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00550                                            TRUE, FALSE, FALSE));
00551 /*
00552             // check if rotator offset don't differ to much
00553             cpl_frame        *f1 = NULL, *f2 = NULL;
00554             cpl_propertylist *h1 = NULL, *h2 = NULL;
00555             char             *kw = NULL;
00556             double           tmp_dbl1 = 0.0, tmp_dbl2 = 0.0;
00557 
00558             KMO_TRY_EXIT_IF_NULL(
00559                 f1 = kmo_dfs_get_frame(frameset, XCAL));
00560 
00561             KMO_TRY_EXIT_IF_NULL(
00562                 f2 = kmo_dfs_get_frame(frameset, input_frame_name));
00563             h1 = kmclipm_propertylist_load(cpl_frame_get_filename(f1), 0);
00564             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00565                 cpl_msg_error("","File not found: %s!",
00566                               cpl_frame_get_filename(f1));
00567                 KMO_TRY_CHECK_ERROR_STATE();
00568             }
00569 
00570             h2 = kmclipm_propertylist_load(cpl_frame_get_filename(f2), 0);
00571             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00572                 cpl_msg_error("","File not found: %s!",
00573                               cpl_frame_get_filename(f2));
00574                 KMO_TRY_CHECK_ERROR_STATE();
00575             }
00576             KMO_TRY_EXIT_IF_NULL(
00577                 kw = cpl_sprintf("%s", ROTANGLE));
00578             tmp_dbl1 = cpl_propertylist_get_double(h1, kw);
00579             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00580                 KMO_TRY_ASSURE(1 == 0,
00581                                CPL_ERROR_ILLEGAL_INPUT,
00582                                "keyword \n%s\n of frame %s is missing!",
00583                                keyword, XCAL);
00584             }
00585 
00586             tmp_dbl2 = cpl_propertylist_get_double(h2, kw);
00587             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00588                 KMO_TRY_ASSURE(1 == 0,
00589                                CPL_ERROR_ILLEGAL_INPUT,
00590                                "keyword \n%s\n of frame %s is missing!",
00591                                keyword, input_frame_name);
00592             }
00593 
00594             // strip angles below 0 deg and above 360 deg
00595             kmclipm_strip_angle(&tmp_dbl1);
00596             kmclipm_strip_angle(&tmp_dbl2);
00597 
00598             if (fabs(tmp_dbl1 - tmp_dbl2) > 30.) {
00599                 if ((fabs(tmp_dbl1) < 0.001) && (tmp_dbl2>330) && (tmp_dbl2<360)) {
00600                     // singularity!
00601                     // we have rot=0 for XCAL and rot>330 | rot<360 for input frame
00602                 } else {
00603                 cpl_msg_warning("","The angle of the calibration files (%g deg) "
00604                                 "and the angle of the frame to reconstruct"
00605                                 " (%g deg) differ by %g deg! Think about using "
00606                                 "calibration files matching better the actual "
00607                                 "rotator offset (ESO OCS ROT NAANGLE)",
00608                                 tmp_dbl1, tmp_dbl2,
00609                                 fabs(tmp_dbl1 - tmp_dbl2));
00610                 }
00611             }
00612 
00613             cpl_propertylist_delete(h1); h1 = NULL;
00614             cpl_propertylist_delete(h2); h2 = NULL;
00615             cpl_free(kw); kw = NULL;
00616 */
00617         }
00618 
00619         KMO_TRY_EXIT_IF_NULL(
00620             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00621         KMO_TRY_EXIT_IF_NULL(
00622             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00623         KMO_TRY_EXIT_IF_NULL(
00624             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00625 
00626         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00627         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00628         cpl_msg_info("", "-------------------------------------------");
00629 
00630 
00631         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00632         KMO_TRY_CHECK_ERROR_STATE();
00633 
00634         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00635                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00636                        (desc1.ex_badpix == FALSE) &&
00637                        ((desc1.fits_type == raw_fits) ||
00638                         (desc1.fits_type == f2d_fits)) &&
00639                        (desc1.frame_type == detector_frame),
00640                        CPL_ERROR_ILLEGAL_INPUT,
00641                        "The frame to reconstruct isn't in the correct format!!!"
00642                        "Exactly 3 frames, or 6 with noise are expected!");
00643 
00644         if (!desc1.ex_noise) {
00645             nr_devices = desc1.nr_ext;
00646         } else {
00647             nr_devices = desc1.nr_ext / 2;
00648         }
00649 
00650         // compare descriptor of XCAL and data frame to reconstruct
00651         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00652         KMO_TRY_CHECK_ERROR_STATE();
00653 
00654         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00655                        (desc1.ex_badpix == desc2.ex_badpix) &&
00656                        (desc1.frame_type == desc2.frame_type),
00657                        CPL_ERROR_ILLEGAL_INPUT,
00658                        "XCAL isn't in the correct format!!!");
00659 
00660         kmo_free_fits_desc(&desc2);
00661 
00662         // compare descriptor of YCAL and data frame to reconstruct
00663         kmo_init_fits_desc(&desc2);
00664 
00665         KMO_TRY_EXIT_IF_NULL(
00666             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00667 
00668         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
00669         KMO_TRY_CHECK_ERROR_STATE();
00670 
00671         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00672                        (desc1.ex_badpix == desc2.ex_badpix) &&
00673                        (desc1.frame_type == desc2.frame_type),
00674                        CPL_ERROR_ILLEGAL_INPUT,
00675                        "YCAL isn't in the correct format!!!");
00676 
00677         kmo_free_fits_desc(&desc2);
00678 
00679         // compare descriptor of LCAL and data frame to reconstruct
00680         kmo_init_fits_desc(&desc2);
00681 
00682         KMO_TRY_EXIT_IF_NULL(
00683             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00684 
00685         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
00686         KMO_TRY_CHECK_ERROR_STATE();
00687 
00688         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00689                        (desc1.ex_badpix == desc2.ex_badpix) &&
00690                        (desc1.frame_type == desc2.frame_type),
00691                        CPL_ERROR_ILLEGAL_INPUT,
00692                        "LCAL isn't in the correct format!!!");
00693 
00694         kmo_free_fits_desc(&desc2);
00695 
00696         //
00697         // --- load, update & save primary header ---
00698         //
00699         KMO_TRY_EXIT_IF_NULL(
00700             main_header = kmo_dfs_load_primary_header(frameset,
00701                                                       input_frame_name));
00702 
00703         KMO_TRY_EXIT_IF_NULL(
00704             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00705 
00706         // assert that filters have correct IDs and that all detectors of all
00707         // input frames have the same filter set
00708         for (i = 1; i <= nr_devices; i++) {
00709             // ESO INS FILTi ID
00710             KMO_TRY_EXIT_IF_NULL(
00711                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00712                                       IFU_FILTID_POSTFIX));
00713 
00714             KMO_TRY_EXIT_IF_NULL(
00715                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00716 
00717             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00718                            (strcmp(filter_id, "YJ") == 0) ||
00719                            (strcmp(filter_id, "H") == 0) ||
00720                            (strcmp(filter_id, "K") == 0) ||
00721                            (strcmp(filter_id, "HK") == 0),
00722                            CPL_ERROR_ILLEGAL_INPUT,
00723                            "Filter ID in primary header of LCAL frame must "
00724                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00725                            "\"HK\" !");
00726 
00727             if (strcmp(input_frame_name, DARK) != 0) {
00728                 // dark needn't to be taken with filter!
00729 
00730                 KMO_TRY_EXIT_IF_NULL(
00731                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00732                                                                 keyword));
00733                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00734                                CPL_ERROR_ILLEGAL_INPUT,
00735                                "Filter IDs must be the same for LCAL frame and "
00736                                "the frame to reconstruct!"
00737                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00738                                i, filter_id, input_frame_name, filter_id_tmp);
00739             }
00740             cpl_free(keyword); keyword = NULL;
00741         }
00742         KMO_TRY_EXIT_IF_NULL(
00743             my_filter_id = cpl_strdup(filter_id));
00744         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00745 
00746         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00747         KMO_TRY_CHECK_ERROR_STATE();
00748 
00749         KMO_TRY_EXIT_IF_NULL(
00750             filename_cube = cpl_sprintf("%s", output_frame_name));
00751         KMO_TRY_EXIT_IF_NULL(
00752             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00753         if (outputextension) {
00754             KMO_TRY_EXIT_IF_NULL(
00755                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00756         } else {
00757             KMO_TRY_EXIT_IF_NULL(
00758                 obs_suffix = cpl_sprintf("%s", ""));
00759         }
00760 
00761         KMO_TRY_EXIT_IF_ERROR(
00762             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00763                                      rec_frame, NULL, parlist, cpl_func));
00764 
00765         // setup grid definition, wavelength start and end points will be set
00766         // in the detector loop
00767         KMO_TRY_EXIT_IF_ERROR(
00768             kmclipm_setup_grid(&gd, imethod, neighborhoodRange));
00769 
00770         KMO_TRY_EXIT_IF_NULL(
00771             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00772 
00773         KMO_TRY_EXIT_IF_NULL(
00774             bounds = kmclipm_extract_bounds(tmp_header));
00775         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00776 
00777         if (detectorimage == TRUE) {
00778             KMO_TRY_EXIT_IF_ERROR(
00779                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00780                                          rec_frame, NULL, parlist, cpl_func));
00781         }
00782 
00783         /* loop through all detectors */
00784         for (i = 1; i <= nr_devices; i++) {
00785             cpl_msg_info("","Processing detector No. %d", i);
00786 
00787             // load lcal
00788             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00789             // doesn't differ too much with different ROTANGLEs.
00790             double rotangle_found;
00791             KMO_TRY_EXIT_IF_NULL(
00792                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00793                                               FALSE, NULL, &rotangle_found));
00794 
00795             char *tmp_band_method = getenv("KMO_BAND_METHOD");
00796             int band_method = 0;
00797             if (tmp_band_method != NULL) {
00798                 band_method = atoi(tmp_band_method);
00799             }
00800 
00801             KMO_TRY_EXIT_IF_NULL(
00802                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00803 
00804             KMO_TRY_EXIT_IF_ERROR(
00805                 kmclipm_setup_grid_band_lcal(&gd, lcal, my_filter_id,
00806                                              band_method, band_table));
00807             cpl_table_delete(band_table); band_table = NULL;
00808 
00809             cpl_image_delete(lcal); lcal = NULL;
00810 
00811             if (detectorimage == TRUE) {
00812                 KMO_TRY_EXIT_IF_NULL(
00813                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00814                                                       gd.l.dim, CPL_TYPE_FLOAT));
00815                 KMO_TRY_EXIT_IF_NULL(
00816                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00817 
00818                 KMO_TRY_EXIT_IF_NULL(
00819                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00820                                                       gd.l.dim, CPL_TYPE_FLOAT));
00821                 KMO_TRY_EXIT_IF_NULL(
00822                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00823             }
00824 
00825 
00826             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00827                 /* update sub-header */
00828                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00829 
00830                 /* load raw image and sub-header*/
00831                 KMO_TRY_EXIT_IF_NULL(
00832                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00833                                                          i, FALSE));
00834                 KMO_TRY_EXIT_IF_NULL(
00835                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00836 
00837                 // check if IFU is valid according to main header keywords &
00838                 // calibration files
00839 
00840                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00841                     KMO_TRY_EXIT_IF_NULL(
00842                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00843                                               IFU_VALID_POSTFIX));
00844                     KMO_TRY_CHECK_ERROR_STATE();
00845                     cpl_propertylist_get_string(main_header, keyword);
00846                     cpl_free(keyword); keyword = NULL;
00847                 } else {
00848                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00849                     // reconstructed
00850                     cpl_propertylist_get_string(main_header, "ggg");
00851                 }
00852 
00853                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00854                     (bounds[2*(ifu_nr-1)] != -1) &&
00855                     (bounds[2*(ifu_nr-1)+1] != -1))
00856                 {
00857                     cpl_error_reset();
00858                     // IFU is valid
00859                     actual_sub_header = sub_header;
00860 
00861                     // calculate WCS
00862                     KMO_TRY_EXIT_IF_ERROR(
00863                         kmo_calc_wcs(main_header, actual_sub_header, ifu_nr,
00864                                      gd.l.start, gd.l.delta));
00865 
00866                     // reconstruct data and noise (if available)
00867                     if (j == 0) {
00868                         sat_mode_msg = FALSE;
00869                     } else {
00870                         sat_mode_msg = TRUE;
00871                     }
00872                     KMO_TRY_EXIT_IF_ERROR(
00873                         kmo_reconstruct_sci(ifu_nr,
00874                                             bounds[2*(ifu_nr-1)],
00875                                             bounds[2*(ifu_nr-1)+1],
00876                                             rec_frame,
00877                                             input_frame_name,
00878                                             NULL,
00879                                             NULL,
00880                                             NULL,
00881                                             xcal_frame,
00882                                             ycal_frame,
00883                                             lcal_frame,
00884                                             &gd,
00885                                             &cube_data,
00886                                             &cube_noise,
00887                                             flux));
00888                 } else {
00889                     // IFU is invalid
00890                     actual_sub_header = sub_header_orig;
00891                     cpl_error_reset();
00892                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
00893 
00894                 if (detectorimage) {
00895                     if (cube_data != NULL) {
00896                         for (int l=0; l<gd.l.dim; l++) {
00897                             KMO_TRY_EXIT_IF_NULL(
00898                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
00899                             for (int y=0; y<gd.y.dim; y++) {
00900                                 for (int x=0; x<gd.x.dim; x++) {
00901                                     int ix = x +
00902                                              y * gd.x.dim +
00903                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00904                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00905                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
00906                                 }
00907                             }
00908                         }
00909                     }
00910                     if (cube_noise != NULL) {
00911                         if (detectorimage) {
00912                             detImgCube = TRUE;
00913                         }
00914                         for (int l=0; l<gd.l.dim; l++) {
00915                             KMO_TRY_EXIT_IF_NULL(
00916                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
00917                             for (int y=0; y<gd.y.dim; y++) {
00918                                 for (int x=0; x<gd.x.dim; x++) {
00919                                     int ix = x +
00920                                              y * gd.x.dim +
00921                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00922                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00923                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
00924                                 }
00925                             }
00926                         }
00927                     }
00928                 }
00929 
00930                 // save output
00931                 KMO_TRY_EXIT_IF_NULL(
00932                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
00933                                                   EXT_DATA));
00934 
00935                 KMO_TRY_EXIT_IF_ERROR(
00936                     kmclipm_update_property_string(actual_sub_header,
00937                                             EXTNAME,
00938                                             extname,
00939                                             "FITS extension name"));
00940 
00941                 cpl_free(extname); extname = NULL;
00942 
00943                 KMO_TRY_EXIT_IF_ERROR(
00944                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
00945                                       actual_sub_header, 0./0.));
00946 
00947                 if (cube_noise != NULL) {
00948                     KMO_TRY_EXIT_IF_NULL(
00949                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
00950                                                       EXT_NOISE));
00951 
00952                     KMO_TRY_EXIT_IF_ERROR(
00953                         kmclipm_update_property_string(actual_sub_header,
00954                                                 EXTNAME,
00955                                                 extname,
00956                                                 "FITS extension name"));
00957 
00958                     cpl_free(extname); extname = NULL;
00959 
00960                     KMO_TRY_EXIT_IF_ERROR(
00961                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
00962                                           actual_sub_header, 0./0.));
00963                 }
00964 
00965                 cpl_imagelist_delete(cube_data); cube_data = NULL;
00966                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
00967                 cpl_propertylist_delete(sub_header); sub_header = NULL;
00968                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
00969             } // for j IFUs
00970 
00971             if (detectorimage) {
00972                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
00973                                            i, FALSE);
00974                 KMO_TRY_CHECK_ERROR_STATE();
00975 
00976                 KMO_TRY_EXIT_IF_NULL(
00977                     tmp_header = kmclipm_propertylist_load(
00978                                          cpl_frame_get_filename(rec_frame), index));
00979                 KMO_TRY_EXIT_IF_ERROR(
00980                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
00981                                          obs_suffix, tmp_header, dev_flip, FALSE));
00982                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00983 
00984                 if (detImgCube) {
00985                     if (desc1.ex_noise) {
00986                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
00987                                                    i, TRUE);
00988                         KMO_TRY_CHECK_ERROR_STATE();
00989                     } else {
00990                         // use same index as for data frame, since input frame
00991                         // has just 3 extensions
00992                     }
00993                     KMO_TRY_EXIT_IF_NULL(
00994                         tmp_header = kmclipm_propertylist_load(
00995                                              cpl_frame_get_filename(rec_frame), index));
00996                     KMO_TRY_EXIT_IF_ERROR(
00997                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
00998                                              obs_suffix, tmp_header, dev_flip, TRUE));
00999                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01000                 }
01001             }
01002 
01003             // free memory
01004             cpl_imagelist_delete(cube_data); cube_data = NULL;
01005             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01006             cpl_propertylist_delete(sub_header); sub_header = NULL;
01007             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01008         } // for i devices
01009     }
01010     KMO_CATCH
01011     {
01012         KMO_CATCH_MSG();
01013         ret_val = -1;
01014     }
01015 
01016     kmo_free_fits_desc(&desc1);
01017     kmo_free_fits_desc(&desc2);
01018     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
01019         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01020         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01021     }
01022     cpl_free(my_filter_id); my_filter_id = NULL;
01023     cpl_free(bounds); bounds = NULL;
01024     cpl_propertylist_delete(main_header); main_header = NULL;
01025     cpl_propertylist_delete(sub_header); sub_header = NULL;
01026     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01027     cpl_imagelist_delete(cube_data); cube_data = NULL;
01028     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01029     cpl_free(obs_suffix); obs_suffix = NULL;
01030     cpl_free(suffix); suffix = NULL;
01031     cpl_free(filename_img); filename_img = NULL;
01032     cpl_free(filename_cube); filename_cube = NULL;
01033     sat_mode_msg = FALSE;
01034 
01035     return ret_val;
01036 }
01037