KMOS Pipeline Reference Manual  1.1.0
kmo_reconstruct.c
00001 /* $Id: kmo_reconstruct.c,v 1.38 2013/03/18 11:52:13 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/03/18 11:52:13 $
00024  * $Revision: 1.38 $
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     /* --dev_flip */
00265     p = cpl_parameter_new_value("kmos.kmo_reconstruct.dev_flip",
00266                                 CPL_TYPE_BOOL,
00267                                 "INTENDED FOR PIPELINE DEVELOPERS ONLY: "
00268                                 "Set this parameter to TRUE if the wavelengths "
00269                                 "are ascending on the detector from bottom to "
00270                                 "top (only for old simulation data).",
00271                                 "kmos.kmo_reconstruct",
00272                                 FALSE);
00273     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_flip");
00274     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00275     cpl_parameterlist_append(recipe->parameters, p);
00276 
00277     // add parameters for band-definition
00278     kmo_band_pars_create(recipe->parameters,
00279                          "kmos.kmo_reconstruct");
00280 
00281     return 0;
00282 }
00283 
00289 static int kmo_reconstruct_exec(cpl_plugin *plugin)
00290 {
00291     cpl_recipe  *recipe;
00292 
00293     /* Get the recipe out of the plugin */
00294     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00295         recipe = (cpl_recipe *)plugin;
00296     else return -1;
00297 
00298     return kmo_reconstruct(recipe->parameters, recipe->frames);
00299 }
00300 
00306 static int kmo_reconstruct_destroy(cpl_plugin *plugin)
00307 {
00308     cpl_recipe *recipe;
00309 
00310     /* Get the recipe out of the plugin */
00311     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00312         recipe = (cpl_recipe *)plugin;
00313     else return -1 ;
00314 
00315     cpl_parameterlist_delete(recipe->parameters);
00316     return 0 ;
00317 }
00318 
00333 static int kmo_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00334 {
00335     int                 ret_val                 = 0,
00336                         nr_devices              = 0,
00337                         i                       = 0,
00338                         j                       = 0,
00339                         flux                    = 0,
00340                         index                   = 0,
00341                         detectorimage           = 0,
00342                         *bounds                 = NULL,
00343                         ifu_nr                  = 0,
00344                         obs_id                  = 0,
00345                         file_extension          = FALSE,
00346                         dev_flip                = FALSE,
00347                         detImgCube              = FALSE;
00348     float               *pdet_img_data          = NULL,
00349                         *pdet_img_noise         = NULL,
00350                         *slice                  = NULL;
00351     double              neighborhoodRange       = 1.001;
00352 
00353     const char          *imethod                = NULL,
00354                         *input_frame_name       = NULL,
00355                         *output_frame_name      = NULL,
00356                         *filter_id              = NULL,
00357                         *filter_id_tmp          = NULL;
00358     char                *keyword                = NULL,
00359                         *filename_cube          = NULL,
00360                         *filename_img           = NULL,
00361 //                        *fn_lut                 = NULL,
00362                         *suffix                 = NULL,
00363                         *obs_suffix             = NULL,
00364                         *my_filter_id           = NULL,
00365                         *extname                = NULL;
00366     cpl_image           *lcal                   = NULL,
00367                         *det_img_data[KMOS_NR_DETECTORS],
00368                         *det_img_noise[KMOS_NR_DETECTORS];
00369     cpl_imagelist       *cube_data              = NULL,
00370                         *cube_noise             = NULL;
00371     cpl_frame           *rec_frame              = NULL,
00372                         *xcal_frame             = NULL,
00373                         *ycal_frame             = NULL,
00374                         *lcal_frame             = NULL;
00375     cpl_propertylist    *main_header           = NULL,
00376                         *sub_header            = NULL,
00377                         *sub_header_orig       = NULL,
00378                         *actual_sub_header     = NULL,
00379                         *tmp_header            = NULL;
00380     cpl_table           *band_table            = NULL;
00381     gridDefinition      gd;
00382     main_fits_desc      desc1,
00383                         desc2;
00384 
00385     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
00386         det_img_data[i] = NULL;
00387         det_img_noise[i] = NULL;
00388     }
00389 
00390     KMO_TRY
00391     {
00392         kmo_init_fits_desc(&desc1);
00393         kmo_init_fits_desc(&desc2);
00394 
00395         // --- check input ---
00396         KMO_TRY_ASSURE((parlist != NULL) &&
00397                        (frameset != NULL),
00398                        CPL_ERROR_NULL_INPUT,
00399                        "Not all input data is provided!");
00400 
00401         KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00402                        (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) ||
00403                        (cpl_frameset_count_tags(frameset, ARC_ON) == 1) ||
00404                        (cpl_frameset_count_tags(frameset, OBJECT) == 1) ||
00405                        (cpl_frameset_count_tags(frameset, STD) == 1) ||
00406                        (cpl_frameset_count_tags(frameset, SCIENCE) == 1),
00407                        CPL_ERROR_NULL_INPUT,
00408                        "A data frame (DARK, FLAT_ON, ARC_ON, OBJECT, STD or SCIENCE) must "
00409                        "be provided!");
00410 
00411         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00412                        CPL_ERROR_FILE_NOT_FOUND,
00413                        "XCAL frame missing in frameset!!");
00414 
00415         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00416                        CPL_ERROR_FILE_NOT_FOUND,
00417                        "YCAL frame missing in frameset!!");
00418 
00419         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00420                        CPL_ERROR_FILE_NOT_FOUND,
00421                        "LCAL frame missing in frameset!!");
00422 
00423         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00424                        CPL_ERROR_FILE_NOT_FOUND,
00425                        "WAVE_BAND frame missing in frameset!!");
00426 
00427         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_reconstruct") == 1,
00428                        CPL_ERROR_ILLEGAL_INPUT,
00429                        "Cannot identify RAW and CALIB frames!");
00430 
00431         // --- get parameters ---
00432         cpl_msg_info("", "--- Parameter setup for kmo_reconstruct ---");
00433 
00434         KMO_TRY_EXIT_IF_NULL(
00435             imethod = kmo_dfs_get_parameter_string(parlist,
00436                                               "kmos.kmo_reconstruct.imethod"));
00437 
00438         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00439                        (strcmp(imethod, "lwNN") == 0) ||
00440                        (strcmp(imethod, "swNN") == 0) ||
00441                        (strcmp(imethod, "MS") == 0) ||
00442                        (strcmp(imethod, "CS") == 0),
00443                        CPL_ERROR_ILLEGAL_INPUT,
00444                        "imethod must be either \"NN\", \"lwNN\", "
00445                        "\"swNN\", \"MS\" or \"CS\"!");
00446 
00447         KMO_TRY_EXIT_IF_ERROR(
00448             kmo_dfs_print_parameter_help(parlist,
00449                                         "kmos.kmo_reconstruct.imethod"));
00450 
00451         flux = kmo_dfs_get_parameter_bool(parlist,
00452                                           "kmos.kmo_reconstruct.flux");
00453 
00454         KMO_TRY_ASSURE((flux == 0) ||
00455                        (flux == 1),
00456                        CPL_ERROR_ILLEGAL_INPUT,
00457                        "flux must be either FALSE or TRUE!");
00458 
00459         KMO_TRY_EXIT_IF_ERROR(
00460             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.flux"));
00461 
00462         detectorimage = kmo_dfs_get_parameter_bool(parlist,
00463                                           "kmos.kmo_reconstruct.detectorimage");
00464 
00465         KMO_TRY_ASSURE((detectorimage == 0) ||
00466                        (detectorimage == 1),
00467                        CPL_ERROR_ILLEGAL_INPUT,
00468                        "detectorimage must be either 0 or 1 !");
00469 
00470         KMO_TRY_EXIT_IF_ERROR(
00471             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.detectorimage"));
00472 
00473         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00474                 "kmos.kmo_reconstruct.neighborhoodRange");
00475         KMO_TRY_CHECK_ERROR_STATE();
00476 
00477         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00478                 CPL_ERROR_ILLEGAL_INPUT,
00479                 "neighborhoodRange must be greater than 0.0");
00480 
00481         KMO_TRY_EXIT_IF_ERROR(
00482             kmo_dfs_print_parameter_help(parlist,
00483                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00484 
00485         kmo_band_pars_load(parlist, "kmos.kmo_reconstruct");
00486 
00487         file_extension = kmo_dfs_get_parameter_bool(parlist,
00488                                         "kmos.kmo_reconstruct.file_extension");
00489         KMO_TRY_CHECK_ERROR_STATE();
00490 
00491         KMO_TRY_EXIT_IF_ERROR(
00492            kmo_dfs_print_parameter_help(parlist,
00493                                        "kmos.kmo_reconstruct.file_extension"));
00494 
00495         dev_flip = kmo_dfs_get_parameter_bool(parlist,
00496                                            "kmos.kmo_reconstruct.dev_flip");
00497         KMO_TRY_CHECK_ERROR_STATE();
00498         KMO_TRY_EXIT_IF_ERROR(
00499             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_reconstruct.dev_flip"));
00500         KMO_TRY_ASSURE((dev_flip == TRUE) ||
00501                        (dev_flip == FALSE),
00502                        CPL_ERROR_ILLEGAL_INPUT,
00503                        "dev_flip must be TRUE or FALSE!");
00504 
00505 
00506         cpl_msg_info("", "-------------------------------------------");
00507 
00508         // load descriptor and header of data frame to reconstruct
00509         if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00510             input_frame_name = DARK;
00511             output_frame_name = CUBE_DARK;
00512         } else if (cpl_frameset_count_tags(frameset, FLAT_ON) == 1) {
00513             input_frame_name = FLAT_ON;
00514             output_frame_name = CUBE_FLAT;
00515         } else if (cpl_frameset_count_tags(frameset, ARC_ON) == 1) {
00516             input_frame_name = ARC_ON;
00517             output_frame_name = CUBE_ARC;
00518         } else if (cpl_frameset_count_tags(frameset, OBJECT) == 1) {
00519             input_frame_name = OBJECT;
00520             output_frame_name = CUBE_OBJECT;
00521         } else if (cpl_frameset_count_tags(frameset, STD) == 1) {
00522             input_frame_name = STD;
00523             output_frame_name = CUBE_STD;
00524         } else if (cpl_frameset_count_tags(frameset, SCIENCE) == 1) {
00525             input_frame_name = SCIENCE;
00526             output_frame_name = CUBE_SCIENCE;
00527         }
00528 
00529         // assure that filters, grating and rotation offsets match for
00530         // XCAL, YCAL, LCAL and for data frame to reconstruct (except DARK
00531         // frames)
00532         // check if filter_id and grating_id match for all detectors
00533         KMO_TRY_EXIT_IF_ERROR(
00534             kmo_check_frame_setup(frameset, XCAL, YCAL,
00535                                        TRUE, FALSE, TRUE));
00536         KMO_TRY_EXIT_IF_ERROR(
00537             kmo_check_frame_setup(frameset, XCAL, LCAL,
00538                                        TRUE, FALSE, TRUE));
00539 
00540 // This check doesn't make sense here since OCS.ROT.NAANGLE is compared.
00541 // When creating the calibration files the RAW exposures needn't have been
00542 // provided in the same order
00543 //        KMO_TRY_EXIT_IF_ERROR(
00544 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00545 //        KMO_TRY_EXIT_IF_ERROR(
00546 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00547 
00548         if (cpl_frameset_count_tags(frameset, DARK) != 1) {
00549 
00550             // check if filters, gratings and rotator offset match
00551             // (except for DARK frames)
00552             KMO_TRY_EXIT_IF_ERROR(
00553                 kmo_check_frame_setup(frameset, XCAL, input_frame_name,
00554                                            TRUE, FALSE, FALSE));
00555 /*
00556             // check if rotator offset don't differ to much
00557             cpl_frame        *f1 = NULL, *f2 = NULL;
00558             cpl_propertylist *h1 = NULL, *h2 = NULL;
00559             char             *kw = NULL;
00560             double           tmp_dbl1 = 0.0, tmp_dbl2 = 0.0;
00561 
00562             KMO_TRY_EXIT_IF_NULL(
00563                 f1 = kmo_dfs_get_frame(frameset, XCAL));
00564 
00565             KMO_TRY_EXIT_IF_NULL(
00566                 f2 = kmo_dfs_get_frame(frameset, input_frame_name));
00567             h1 = kmclipm_propertylist_load(cpl_frame_get_filename(f1), 0);
00568             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00569                 cpl_msg_error("","File not found: %s!",
00570                               cpl_frame_get_filename(f1));
00571                 KMO_TRY_CHECK_ERROR_STATE();
00572             }
00573 
00574             h2 = kmclipm_propertylist_load(cpl_frame_get_filename(f2), 0);
00575             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00576                 cpl_msg_error("","File not found: %s!",
00577                               cpl_frame_get_filename(f2));
00578                 KMO_TRY_CHECK_ERROR_STATE();
00579             }
00580             KMO_TRY_EXIT_IF_NULL(
00581                 kw = cpl_sprintf("%s", ROTANGLE));
00582             tmp_dbl1 = cpl_propertylist_get_double(h1, kw);
00583             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00584                 KMO_TRY_ASSURE(1 == 0,
00585                                CPL_ERROR_ILLEGAL_INPUT,
00586                                "keyword \n%s\n of frame %s is missing!",
00587                                keyword, XCAL);
00588             }
00589 
00590             tmp_dbl2 = cpl_propertylist_get_double(h2, kw);
00591             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00592                 KMO_TRY_ASSURE(1 == 0,
00593                                CPL_ERROR_ILLEGAL_INPUT,
00594                                "keyword \n%s\n of frame %s is missing!",
00595                                keyword, input_frame_name);
00596             }
00597 
00598             // strip angles below 0 deg and above 360 deg
00599             kmclipm_strip_angle(&tmp_dbl1);
00600             kmclipm_strip_angle(&tmp_dbl2);
00601 
00602             if (fabs(tmp_dbl1 - tmp_dbl2) > 30.) {
00603                 if ((fabs(tmp_dbl1) < 0.001) && (tmp_dbl2>330) && (tmp_dbl2<360)) {
00604                     // singularity!
00605                     // we have rot=0 for XCAL and rot>330 | rot<360 for input frame
00606                 } else {
00607                 cpl_msg_warning("","The angle of the calibration files (%g deg) "
00608                                 "and the angle of the frame to reconstruct"
00609                                 " (%g deg) differ by %g deg! Think about using "
00610                                 "calibration files matching better the actual "
00611                                 "rotator offset (ESO OCS ROT NAANGLE)",
00612                                 tmp_dbl1, tmp_dbl2,
00613                                 fabs(tmp_dbl1 - tmp_dbl2));
00614                 }
00615             }
00616 
00617             cpl_propertylist_delete(h1); h1 = NULL;
00618             cpl_propertylist_delete(h2); h2 = NULL;
00619             cpl_free(kw); kw = NULL;
00620 */
00621         }
00622 
00623         KMO_TRY_EXIT_IF_NULL(
00624             xcal_frame = kmo_dfs_get_frame(frameset, XCAL));
00625         KMO_TRY_EXIT_IF_NULL(
00626             rec_frame = kmo_dfs_get_frame(frameset, input_frame_name));
00627         KMO_TRY_EXIT_IF_NULL(
00628             suffix = kmo_dfs_get_suffix(rec_frame, TRUE, TRUE));
00629 
00630         KMO_TRY_EXIT_IF_ERROR(
00631             kmo_check_frame_setup_md5(frameset));
00632 
00633         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00634         cpl_msg_info("", "(grating 1, 2 & 3, rotation angle)");
00635         cpl_msg_info("", "-------------------------------------------");
00636 
00637 
00638         desc1 = kmo_identify_fits_header(cpl_frame_get_filename(rec_frame));
00639         KMO_TRY_CHECK_ERROR_STATE();
00640 
00641         KMO_TRY_ASSURE(((desc1.nr_ext == KMOS_NR_DETECTORS) ||
00642                         ((desc1.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00643                        (desc1.ex_badpix == FALSE) &&
00644                        ((desc1.fits_type == raw_fits) ||
00645                         (desc1.fits_type == f2d_fits)) &&
00646                        (desc1.frame_type == detector_frame),
00647                        CPL_ERROR_ILLEGAL_INPUT,
00648                        "The frame to reconstruct isn't in the correct format!!!"
00649                        "Exactly 3 frames, or 6 with noise are expected!");
00650 
00651         if (!desc1.ex_noise) {
00652             nr_devices = desc1.nr_ext;
00653         } else {
00654             nr_devices = desc1.nr_ext / 2;
00655         }
00656 
00657         // compare descriptor of XCAL and data frame to reconstruct
00658         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(xcal_frame));
00659         KMO_TRY_CHECK_ERROR_STATE();
00660 
00661         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00662                        (desc1.ex_badpix == desc2.ex_badpix) &&
00663                        (desc1.frame_type == desc2.frame_type),
00664                        CPL_ERROR_ILLEGAL_INPUT,
00665                        "XCAL isn't in the correct format!!!");
00666 
00667         kmo_free_fits_desc(&desc2);
00668 
00669         // compare descriptor of YCAL and data frame to reconstruct
00670         kmo_init_fits_desc(&desc2);
00671 
00672         KMO_TRY_EXIT_IF_NULL(
00673             ycal_frame = kmo_dfs_get_frame(frameset, YCAL));
00674 
00675         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(ycal_frame));
00676         KMO_TRY_CHECK_ERROR_STATE();
00677 
00678         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00679                        (desc1.ex_badpix == desc2.ex_badpix) &&
00680                        (desc1.frame_type == desc2.frame_type),
00681                        CPL_ERROR_ILLEGAL_INPUT,
00682                        "YCAL isn't in the correct format!!!");
00683 
00684         kmo_free_fits_desc(&desc2);
00685 
00686         // compare descriptor of LCAL and data frame to reconstruct
00687         kmo_init_fits_desc(&desc2);
00688 
00689         KMO_TRY_EXIT_IF_NULL(
00690             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00691 
00692         desc2 = kmo_identify_fits_header(cpl_frame_get_filename(lcal_frame));
00693         KMO_TRY_CHECK_ERROR_STATE();
00694 
00695         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00696                        (desc1.ex_badpix == desc2.ex_badpix) &&
00697                        (desc1.frame_type == desc2.frame_type),
00698                        CPL_ERROR_ILLEGAL_INPUT,
00699                        "LCAL isn't in the correct format!!!");
00700 
00701         kmo_free_fits_desc(&desc2);
00702 
00703         //
00704         // --- load, update & save primary header ---
00705         //
00706         KMO_TRY_EXIT_IF_NULL(
00707             main_header = kmo_dfs_load_primary_header(frameset,
00708                                                       input_frame_name));
00709 
00710         KMO_TRY_EXIT_IF_NULL(
00711             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00712 
00713         // assert that filters have correct IDs and that all detectors of all
00714         // input frames have the same filter set
00715         for (i = 1; i <= nr_devices; i++) {
00716             // ESO INS FILTi ID
00717             KMO_TRY_EXIT_IF_NULL(
00718                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00719                                       IFU_FILTID_POSTFIX));
00720 
00721             KMO_TRY_EXIT_IF_NULL(
00722                 filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00723 
00724             KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00725                            (strcmp(filter_id, "YJ") == 0) ||
00726                            (strcmp(filter_id, "H") == 0) ||
00727                            (strcmp(filter_id, "K") == 0) ||
00728                            (strcmp(filter_id, "HK") == 0),
00729                            CPL_ERROR_ILLEGAL_INPUT,
00730                            "Filter ID in primary header of LCAL frame must "
00731                            "be either \"IZ\", \"YJ\", \"H\", \"K\" or "
00732                            "\"HK\" !");
00733 
00734             if (strcmp(input_frame_name, DARK) != 0) {
00735                 // dark needn't to be taken with filter!
00736 
00737                 KMO_TRY_EXIT_IF_NULL(
00738                     filter_id_tmp = cpl_propertylist_get_string(main_header,
00739                                                                 keyword));
00740                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_tmp) == 0,
00741                                CPL_ERROR_ILLEGAL_INPUT,
00742                                "Filter IDs must be the same for LCAL frame and "
00743                                "the frame to reconstruct!"
00744                                "Detector No.: %d\nLCAL: %s\n%s: %s\n",
00745                                i, filter_id, input_frame_name, filter_id_tmp);
00746             }
00747             cpl_free(keyword); keyword = NULL;
00748         }
00749         KMO_TRY_EXIT_IF_NULL(
00750             my_filter_id = cpl_strdup(filter_id));
00751         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00752 
00753         obs_id = cpl_propertylist_get_int(main_header, OBS_ID);
00754         KMO_TRY_CHECK_ERROR_STATE();
00755 
00756         KMO_TRY_EXIT_IF_NULL(
00757             filename_cube = cpl_sprintf("%s", output_frame_name));
00758         KMO_TRY_EXIT_IF_NULL(
00759             filename_img = cpl_sprintf("%s", DET_IMG_REC));
00760         if (file_extension) {
00761             KMO_TRY_EXIT_IF_NULL(
00762                 obs_suffix = cpl_sprintf("%s%d", "_", obs_id));
00763         } else {
00764             KMO_TRY_EXIT_IF_NULL(
00765                 obs_suffix = cpl_sprintf("%s", ""));
00766         }
00767 
00768         KMO_TRY_EXIT_IF_ERROR(
00769             kmo_dfs_save_main_header(frameset, filename_cube, obs_suffix,
00770                                      rec_frame, NULL, parlist, cpl_func));
00771 
00772         // setup grid definition, wavelength start and end points will be set
00773         // in the detector loop
00774         KMO_TRY_EXIT_IF_ERROR(
00775             kmclipm_setup_grid(&gd, imethod, neighborhoodRange));
00776 
00777         KMO_TRY_EXIT_IF_NULL(
00778             tmp_header = kmo_dfs_load_primary_header(frameset, XCAL));
00779 
00780         KMO_TRY_EXIT_IF_NULL(
00781             bounds = kmclipm_extract_bounds(tmp_header));
00782         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00783 
00784         if (detectorimage == TRUE) {
00785             KMO_TRY_EXIT_IF_ERROR(
00786                 kmo_dfs_save_main_header(frameset, filename_img, obs_suffix,
00787                                          rec_frame, NULL, parlist, cpl_func));
00788         }
00789 
00790         /* loop through all detectors */
00791         for (i = 1; i <= nr_devices; i++) {
00792             cpl_msg_info("","Processing detector No. %d", i);
00793 
00794             // load lcal
00795             // extract LCAL image close to ROTANGLE 0. assuming that the wavelength range
00796             // doesn't differ too much with different ROTANGLEs.
00797             double rotangle_found;
00798             KMO_TRY_EXIT_IF_NULL(
00799                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, i, FALSE, 0.,
00800                                               FALSE, NULL, &rotangle_found));
00801 
00802             char *tmp_band_method = getenv("KMO_BAND_METHOD");
00803             int band_method = 0;
00804             if (tmp_band_method != NULL) {
00805                 band_method = atoi(tmp_band_method);
00806             }
00807 
00808             KMO_TRY_EXIT_IF_NULL(
00809                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, FALSE));
00810 
00811             KMO_TRY_EXIT_IF_ERROR(
00812                 kmclipm_setup_grid_band_lcal(&gd, lcal, my_filter_id,
00813                                              band_method, band_table));
00814             cpl_table_delete(band_table); band_table = NULL;
00815 
00816             cpl_image_delete(lcal); lcal = NULL;
00817 
00818             if (detectorimage == TRUE) {
00819                 KMO_TRY_EXIT_IF_NULL(
00820                     det_img_data[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00821                                                       gd.l.dim, CPL_TYPE_FLOAT));
00822                 KMO_TRY_EXIT_IF_NULL(
00823                     pdet_img_data = cpl_image_get_data_float(det_img_data[i-1]));
00824 
00825                 KMO_TRY_EXIT_IF_NULL(
00826                     det_img_noise[i-1] = cpl_image_new(gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR,
00827                                                       gd.l.dim, CPL_TYPE_FLOAT));
00828                 KMO_TRY_EXIT_IF_NULL(
00829                     pdet_img_noise = cpl_image_get_data_float(det_img_noise[i-1]));
00830             }
00831 
00832 
00833             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00834                 /* update sub-header */
00835                 ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00836 
00837                 /* load raw image and sub-header*/
00838                 KMO_TRY_EXIT_IF_NULL(
00839                     sub_header = kmo_dfs_load_sub_header(frameset, input_frame_name,
00840                                                          i, FALSE));
00841                 KMO_TRY_EXIT_IF_NULL(
00842                     sub_header_orig = cpl_propertylist_duplicate(sub_header));
00843 
00844                 // check if IFU is valid according to main header keywords &
00845                 // calibration files
00846 
00847                 if (getenv("KMOS_RECONSTRUCT_ALL") == NULL) {
00848                     KMO_TRY_EXIT_IF_NULL(
00849                         keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
00850                                               IFU_VALID_POSTFIX));
00851                     KMO_TRY_CHECK_ERROR_STATE();
00852                     cpl_propertylist_get_string(main_header, keyword);
00853                     cpl_free(keyword); keyword = NULL;
00854                 } else {
00855                     // if KMOS_RECONSTRUCT_ALL is set all IFUs should be
00856                     // reconstructed
00857                     cpl_propertylist_get_string(main_header, "ggg");
00858                 }
00859 
00860                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00861                     (bounds[2*(ifu_nr-1)] != -1) &&
00862                     (bounds[2*(ifu_nr-1)+1] != -1))
00863                 {
00864                     cpl_error_reset();
00865                     // IFU is valid
00866                     actual_sub_header = sub_header;
00867 
00868                     // calculate WCS
00869                     KMO_TRY_EXIT_IF_ERROR(
00870                         kmo_calc_wcs(main_header, actual_sub_header, ifu_nr,
00871                                      gd.l.start, gd.l.delta));
00872 
00873                     // reconstruct data and noise (if available)
00874                     if (j == 0) {
00875                         sat_mode_msg = FALSE;
00876                     } else {
00877                         sat_mode_msg = TRUE;
00878                     }
00879                     KMO_TRY_EXIT_IF_ERROR(
00880                         kmo_reconstruct_sci(ifu_nr,
00881                                             bounds[2*(ifu_nr-1)],
00882                                             bounds[2*(ifu_nr-1)+1],
00883                                             rec_frame,
00884                                             input_frame_name,
00885                                             NULL,
00886                                             NULL,
00887                                             NULL,
00888                                             xcal_frame,
00889                                             ycal_frame,
00890                                             lcal_frame,
00891                                             &gd,
00892                                             &cube_data,
00893                                             &cube_noise,
00894                                             flux));
00895                 } else {
00896                     // IFU is invalid
00897                     actual_sub_header = sub_header_orig;
00898                     cpl_error_reset();
00899                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ..
00900 
00901                 if (detectorimage) {
00902                     if (cube_data != NULL) {
00903                         for (int l=0; l<gd.l.dim; l++) {
00904                             KMO_TRY_EXIT_IF_NULL(
00905                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_data, l)));
00906                             for (int y=0; y<gd.y.dim; y++) {
00907                                 for (int x=0; x<gd.x.dim; x++) {
00908                                     int ix = x +
00909                                              y * gd.x.dim +
00910                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00911                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00912                                     pdet_img_data[ix] = slice[x + y*gd.x.dim];
00913                                 }
00914                             }
00915                         }
00916                     }
00917                     if (cube_noise != NULL) {
00918                         if (detectorimage) {
00919                             detImgCube = TRUE;
00920                         }
00921                         for (int l=0; l<gd.l.dim; l++) {
00922                             KMO_TRY_EXIT_IF_NULL(
00923                                 slice = cpl_image_get_data_float(cpl_imagelist_get(cube_noise, l)));
00924                             for (int y=0; y<gd.y.dim; y++) {
00925                                 for (int x=0; x<gd.x.dim; x++) {
00926                                     int ix = x +
00927                                              y * gd.x.dim +
00928                                              j * gd.x.dim*gd.y.dim +     //IFU offset
00929                                              l * gd.x.dim*gd.y.dim*KMOS_IFUS_PER_DETECTOR;
00930                                     pdet_img_noise[ix] = slice[x + y*gd.x.dim];
00931                                 }
00932                             }
00933                         }
00934                     }
00935                 }
00936 
00937                 // save output
00938                 KMO_TRY_EXIT_IF_NULL(
00939                     extname = kmo_extname_creator(ifu_frame, ifu_nr,
00940                                                   EXT_DATA));
00941 
00942                 KMO_TRY_EXIT_IF_ERROR(
00943                     kmclipm_update_property_string(actual_sub_header,
00944                                             EXTNAME,
00945                                             extname,
00946                                             "FITS extension name"));
00947 
00948                 cpl_free(extname); extname = NULL;
00949 
00950                 KMO_TRY_EXIT_IF_ERROR(
00951                     kmo_dfs_save_cube(cube_data, filename_cube, obs_suffix,
00952                                       actual_sub_header, 0./0.));
00953 
00954                 if (cube_noise != NULL) {
00955                     KMO_TRY_EXIT_IF_NULL(
00956                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
00957                                                       EXT_NOISE));
00958 
00959                     KMO_TRY_EXIT_IF_ERROR(
00960                         kmclipm_update_property_string(actual_sub_header,
00961                                                 EXTNAME,
00962                                                 extname,
00963                                                 "FITS extension name"));
00964 
00965                     cpl_free(extname); extname = NULL;
00966 
00967                     KMO_TRY_EXIT_IF_ERROR(
00968                         kmo_dfs_save_cube(cube_noise, filename_cube, obs_suffix,
00969                                           actual_sub_header, 0./0.));
00970                 }
00971 
00972                 cpl_imagelist_delete(cube_data); cube_data = NULL;
00973                 cpl_imagelist_delete(cube_noise); cube_noise = NULL;
00974                 cpl_propertylist_delete(sub_header); sub_header = NULL;
00975                 cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
00976             } // for j IFUs
00977 
00978             if (detectorimage) {
00979                 index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
00980                                            i, FALSE);
00981                 KMO_TRY_CHECK_ERROR_STATE();
00982 
00983                 KMO_TRY_EXIT_IF_NULL(
00984                     tmp_header = kmclipm_propertylist_load(
00985                                          cpl_frame_get_filename(rec_frame), index));
00986                 KMO_TRY_EXIT_IF_ERROR(
00987                     kmo_save_det_img_ext(det_img_data[i-1], gd, i, filename_img,
00988                                          obs_suffix, tmp_header, dev_flip, FALSE));
00989                 cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00990 
00991                 if (detImgCube) {
00992                     if (desc1.ex_noise) {
00993                         index = kmo_identify_index(cpl_frame_get_filename(rec_frame),
00994                                                    i, TRUE);
00995                         KMO_TRY_CHECK_ERROR_STATE();
00996                     } else {
00997                         // use same index as for data frame, since input frame
00998                         // has just 3 extensions
00999                     }
01000                     KMO_TRY_EXIT_IF_NULL(
01001                         tmp_header = kmclipm_propertylist_load(
01002                                              cpl_frame_get_filename(rec_frame), index));
01003                     KMO_TRY_EXIT_IF_ERROR(
01004                         kmo_save_det_img_ext(det_img_noise[i-1], gd, i, filename_img,
01005                                              obs_suffix, tmp_header, dev_flip, TRUE));
01006                     cpl_propertylist_delete(tmp_header); tmp_header = NULL;
01007                 }
01008             }
01009 
01010             // free memory
01011             cpl_imagelist_delete(cube_data); cube_data = NULL;
01012             cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01013             cpl_propertylist_delete(sub_header); sub_header = NULL;
01014             cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01015         } // for i devices
01016     }
01017     KMO_CATCH
01018     {
01019         KMO_CATCH_MSG();
01020         ret_val = -1;
01021     }
01022 
01023     kmo_free_fits_desc(&desc1);
01024     kmo_free_fits_desc(&desc2);
01025     for (int i=0; i<KMOS_NR_DETECTORS; i++) {
01026         cpl_image_delete(det_img_data[i]); det_img_data[i] = NULL;
01027         cpl_image_delete(det_img_noise[i]); det_img_noise[i] = NULL;
01028     }
01029     cpl_free(my_filter_id); my_filter_id = NULL;
01030     cpl_free(bounds); bounds = NULL;
01031     cpl_propertylist_delete(main_header); main_header = NULL;
01032     cpl_propertylist_delete(sub_header); sub_header = NULL;
01033     cpl_propertylist_delete(sub_header_orig); sub_header_orig = NULL;
01034     cpl_imagelist_delete(cube_data); cube_data = NULL;
01035     cpl_imagelist_delete(cube_noise); cube_noise = NULL;
01036     cpl_free(obs_suffix); obs_suffix = NULL;
01037     cpl_free(suffix); suffix = NULL;
01038     cpl_free(filename_img); filename_img = NULL;
01039     cpl_free(filename_cube); filename_cube = NULL;
01040     sat_mode_msg = FALSE;
01041 
01042     return ret_val;
01043 }
01044