KMOS Pipeline Reference Manual  1.0.8
kmo_illumination.c
00001 /* $Id: kmo_illumination.c,v 1.36 2013/02/02 17:47:55 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/02/02 17:47:55 $
00024  * $Revision: 1.36 $
00025  * $Name: kmosp_v1_0_8__20130220 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 
00036 #include <math.h>
00037 #include <string.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "kmo_priv_reconstruct.h"
00042 #include "kmo_priv_functions.h"
00043 #include "kmo_functions.h"
00044 #include "kmo_cpl_extensions.h"
00045 #include "kmo_dfs.h"
00046 #include "kmo_error.h"
00047 #include "kmo_constants.h"
00048 #include "kmo_debug.h"
00049 
00050 /*-----------------------------------------------------------------------------
00051  *                          Functions prototypes
00052  *----------------------------------------------------------------------------*/
00053 
00054 static int kmo_illumination_create(cpl_plugin *);
00055 static int kmo_illumination_exec(cpl_plugin *);
00056 static int kmo_illumination_destroy(cpl_plugin *);
00057 static int kmo_illumination(cpl_parameterlist *, cpl_frameset *);
00058 
00059 /*-----------------------------------------------------------------------------
00060  *                          Static variables
00061  *----------------------------------------------------------------------------*/
00062 
00063 static char kmo_illumination_description[] =
00064 "This recipe creates the spatial non-uniformity calibration frame needed for\n"
00065 "all three detectors. It must be called after the kmo_wave_cal-recipe, which\n"
00066 "generates the spectral calibration frame needed in this recipe. As input at\n"
00067 "least a sky, a master dark, a master flat and the spatial and spectral cali-\n"
00068 "bration frames are required.\n"
00069 "\n"
00070 "BASIC PARAMETERS:\n"
00071 "-----------------\n"
00072 "--imethod\n"
00073 "The interpolation method used for reconstruction.\n"
00074 "\n"
00075 "--range\n"
00076 "The spectral range [um] to combine when collapsing the reconstructed cubes.\n"
00077 "\n"
00078 "ADVANCED PARAMETERS\n"
00079 "-------------------\n"
00080 "--neighborhoodRange\n"
00081 "Defines the range to search for neighbors during reconstruction\n"
00082 "\n"
00083 "--b_samples\n"
00084 "The number of samples in spectral direction for the reconstructed cube.\n"
00085 "Ideally this number should be greater than 2048, the detector size.\n"
00086 "\n"
00087 "--b_start\n"
00088 "--b_end\n"
00089 "Used to define manually the start and end wavelength for the reconstructed\n"
00090 "cube. By default the internally defined values are used.\n"
00091 "\n"
00092 "--cmethod\n"
00093 "Following methods of frame combination are available:\n"
00094 "   * 'ksigma' (Default)\n"
00095 "   An iterative sigma clipping. For each position all pixels in the spectrum\n"
00096 "   are examined. If they deviate significantly, they will be rejected according\n"
00097 "   to the conditions:\n"
00098 "       val > mean + stdev * cpos_rej\n"
00099 "   and\n"
00100 "       val < mean - stdev * cneg_rej\n"
00101 "   where --cpos_rej, --cneg_rej and --citer are the corresponding configuration\n"
00102 "   parameters. In the first iteration median and percentile level are used.\n"
00103 "\n"
00104 "   * 'median'\n"
00105 "   At each pixel position the median is calculated.\n"
00106 "\n"
00107 "   * 'average'\n"
00108 "   At each pixel position the average is calculated.\n"
00109 "\n"
00110 "   * 'sum'\n"
00111 "   At each pixel position the sum is calculated.\n"
00112 "\n"
00113 "   * 'min_max'\n"
00114 "   The specified number of minimum and maximum pixel values will be rejected.\n"
00115 "   --cmax and --cmin apply to this method.\n"
00116 "\n"
00117 "--cpos_rej\n"
00118 "--cneg_rej\n"
00119 "--citer\n"
00120 "see --cmethod='ksigma'\n"
00121 "\n"
00122 "--cmax\n"
00123 "--cmin\n"
00124 "see --cmethod='min_max'\n"
00125 "\n"
00126 "-------------------------------------------------------------------------------\n"
00127 "  Input files:\n"
00128 "\n"
00129 "   DO                    KMOS                                                  \n"
00130 "   category              Type   Explanation                    Required #Frames\n"
00131 "   --------              -----  -----------                    -------- -------\n"
00132 "   FLAT_SKY               F2D   Sky exposures                     Y      1-n   \n"
00133 "                                (at least 3 frames recommended)                \n"
00134 "   MASTER_DARK            F2D   Master dark                       Y       1    \n"
00135 "   MASTER_FLAT            F2D   Master flat                       Y       1    \n"
00136 "   XCAL                   F2D   x calibration frame               Y       1    \n"
00137 "   YCAL                   F2D   y calibration frame               Y       1    \n"
00138 "   LCAL                   F2D   Wavelength calib. frame           Y       1    \n"
00139 "   WAVE_BAND              F2L   Table with start-/end-wavelengths Y       1    \n"
00140 "\n"
00141 "  Output files:\n"
00142 "\n"
00143 "   DO                    KMOS\n"
00144 "   category              Type   Explanation\n"
00145 "   --------              -----  -----------\n"
00146 "   ILLUM_CORR            F2I    Illumination calibration frame   \n"
00147 "-------------------------------------------------------------------------------\n"
00148 "\n";
00149 
00150 /*-----------------------------------------------------------------------------
00151  *                              Functions code
00152  *----------------------------------------------------------------------------*/
00153 
00170 int cpl_plugin_get_info(cpl_pluginlist *list)
00171 {
00172     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00173     cpl_plugin *plugin = &recipe->interface;
00174 
00175     cpl_plugin_init(plugin,
00176                         CPL_PLUGIN_API,
00177                         KMOS_BINARY_VERSION,
00178                         CPL_PLUGIN_TYPE_RECIPE,
00179                         "kmo_illumination",
00180                         "Create a calibration frame to correct spatial "
00181                         "non-uniformity of flatfield.",
00182                         kmo_illumination_description,
00183                         "Alex Agudo Berbel",
00184                         "agudo@mpe.mpg.de",
00185                         kmos_get_license(),
00186                         kmo_illumination_create,
00187                         kmo_illumination_exec,
00188                         kmo_illumination_destroy);
00189 
00190     cpl_pluginlist_append(list, plugin);
00191 
00192     return 0;
00193 }
00194 
00202 static int kmo_illumination_create(cpl_plugin *plugin)
00203 {
00204     cpl_recipe *recipe;
00205     cpl_parameter *p;
00206 
00207     /* Check that the plugin is part of a valid recipe */
00208     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00209         recipe = (cpl_recipe *)plugin;
00210     else
00211         return -1;
00212 
00213     /* Create the parameters list in the cpl_recipe object */
00214     recipe->parameters = cpl_parameterlist_new();
00215 
00216     /* Fill the parameters list */
00217     /* --imethod */
00218     p = cpl_parameter_new_value("kmos.kmo_illumination.imethod",
00219                                 CPL_TYPE_STRING,
00220                                 "Method to use for interpolation: "
00221                                 "[\"NN\" (nearest neighbour), "
00222                                 "\"lwNN\" (linear weighted nearest neighbor),"
00223                                 "\"swNN\" (square weighted nearest neighbor)"
00224                                 "\"MS\" (Modified Shepard's method)"
00225                                 "\"CS\" (Cubic spline)]",
00226                                 "kmos.kmo_illumination",
00227                                 "CS");
00228     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00229     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00230     cpl_parameterlist_append(recipe->parameters, p);
00231 
00232     /* --neighborhoodRange */
00233     p = cpl_parameter_new_value("kmos.kmo_illumination.neighborhoodRange",
00234                                 CPL_TYPE_DOUBLE,
00235                                 "Defines the range to search for neighbors."
00236                                 "in pixels",
00237                                 "kmos.kmo_illumination",
00238                                 1.001);
00239     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00240     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00241     cpl_parameterlist_append(recipe->parameters, p);
00242 
00243     /* --range */
00244     p = cpl_parameter_new_value("kmos.kmo_illumination.range",
00245                                 CPL_TYPE_STRING,
00246                                 "The spectral ranges to combine when collapsing"
00247                                 "the reconstructed cubes. e.g."
00248                                 "\"x1_start,x1_end;x2_start,x2_end\" (microns)",
00249                                 "kmos.kmo_illumination",
00250                                 "");
00251     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "range");
00252     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00253     cpl_parameterlist_append(recipe->parameters, p);
00254 
00255     /* --flux */
00256     p = cpl_parameter_new_value("kmos.kmo_illumination.flux",
00257                                 CPL_TYPE_BOOL,
00258                                 "TRUE: Apply flux conservation. FALSE: otherwise",
00259                                 "kmos.kmo_illumination",
00260                                 FALSE);
00261     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00262     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00263     cpl_parameterlist_append(recipe->parameters, p);
00264 
00265     // add parameters for band-definition
00266     kmo_band_pars_create(recipe->parameters,
00267                          "kmos.kmo_illumination");
00268 
00269     // add parameters for combining
00270     return kmo_combine_pars_create(recipe->parameters,
00271                                    "kmos.kmo_illumination",
00272                                    DEF_REJ_METHOD,
00273                                    FALSE);
00274 }
00275 
00281 static int kmo_illumination_exec(cpl_plugin *plugin)
00282 {
00283     cpl_recipe  *recipe;
00284 
00285     /* Get the recipe out of the plugin */
00286     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00287         recipe = (cpl_recipe *)plugin;
00288     else return -1;
00289 
00290     return kmo_illumination(recipe->parameters, recipe->frames);
00291 }
00292 
00298 static int kmo_illumination_destroy(cpl_plugin *plugin)
00299 {
00300     cpl_recipe *recipe;
00301 
00302     /* Get the recipe out of the plugin */
00303     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00304         recipe = (cpl_recipe *)plugin;
00305     else return -1 ;
00306 
00307     cpl_parameterlist_delete(recipe->parameters);
00308     return 0 ;
00309 }
00310 
00325 static int kmo_illumination(cpl_parameterlist *parlist, cpl_frameset *frameset)
00326 {
00327     cpl_table        *band_table                = NULL;
00328 
00329     cpl_vector       *ranges                    = NULL,
00330                      *identified_slices         = NULL;
00331 
00332     cpl_image        *img_in                    = NULL,
00333                      *img_dark                  = NULL,
00334                      *img_dark_noise            = NULL,
00335                      *img_flat                  = NULL,
00336                      *img_flat_noise            = NULL,
00337                      *combined_data             = NULL,
00338                      *combined_noise            = NULL,
00339                      *xcal                      = NULL,
00340                      *ycal                      = NULL,
00341                      *lcal                      = NULL,
00342                      *data_ifu                  = NULL,
00343                      *noise_ifu                 = NULL,
00344                      **stored_data_images       = NULL,
00345                      **stored_noise_images      = NULL;
00346 
00347     cpl_frame        *frame                     = NULL,
00348                      *xcalFrame                 = NULL,
00349                      *ycalFrame                 = NULL,
00350                      *lcalFrame                 = NULL;
00351 
00352     cpl_array        *calTimestamp              = NULL,
00353                      **unused_ifus_before       = NULL,
00354                      **unused_ifus_after        = NULL;
00355 
00356     int              ret_val                    = 0,
00357                      nr_devices                 = 0,
00358                      i                          = 0,
00359                      j                          = 0,
00360                      ifu_nr                     = 0,
00361                      nx                         = 0,
00362                      ny                         = 0,
00363                      process_noise              = FALSE,
00364                      cmax                       = 0,
00365                      cmin                       = 0,
00366                      citer                      = 0,
00367                      det_nr                     = 0,
00368                      *bounds                    = NULL,
00369                      count                      = 0,
00370                      qc_max_dev_id              = 0,
00371                      qc_max_nonunif_id          = 0,
00372                      flux                       = FALSE;
00373 
00374     const int        *punused_ifus              = NULL;
00375 
00376     cpl_propertylist *main_header               = NULL,
00377                      *tmp_header                = NULL,
00378                      *sub_header                = NULL,
00379                      **stored_sub_data_headers  = NULL,
00380                      **stored_sub_noise_headers = NULL;
00381 
00382     cpl_imagelist    *cube_data                 = NULL,
00383                      *cube_noise                = NULL,
00384                      *detector_in               = NULL,
00385                      **stored_data_cubes        = NULL,
00386                      **stored_noise_cubes       = NULL;
00387 
00388     main_fits_desc   desc_sky,
00389                      desc_dark,
00390                      desc_flat,
00391                      desc_xcal,
00392                      desc_ycal,
00393                      desc_lcal;
00394 
00395     const char       *method                    = NULL,
00396                      *cmethod                   = NULL,
00397                      *filter_id                 = NULL,
00398                      *filter_id_l               = NULL,
00399                      *ranges_txt                = NULL;
00400 
00401     char             *keyword                   = NULL,
00402                      *fn_lut                    = NULL,
00403                      *suffix                    = NULL,
00404                      *extname                   = NULL;
00405 
00406 
00407     double           cpos_rej                   = 0.0,
00408                      cneg_rej                   = 0.0,
00409                      neighborhoodRange          = 1.001,
00410                      mean_data                  = 0.0,
00411                      ifu_crpix                  = 0.0,
00412                      ifu_crval                  = 0.0,
00413                      ifu_cdelt                  = 0.0,
00414                      qc_spat_unif               = 0.0,
00415                      qc_max_dev                 = 0.0,
00416                      qc_max_nonunif             = 0.0,
00417                      tmp_stdev                  = 0.0,
00418                      tmp_mean                   = 0.0,
00419                      rotangle                   = 0.0,
00420                      tmp_rotangle               = 0.0,
00421                      rotangle_found             = 0.0;
00422 
00423     gridDefinition gd;
00424 
00425     KMO_TRY
00426     {
00427         kmo_init_fits_desc(&desc_sky);
00428         kmo_init_fits_desc(&desc_dark);
00429         kmo_init_fits_desc(&desc_flat);
00430         kmo_init_fits_desc(&desc_xcal);
00431         kmo_init_fits_desc(&desc_ycal);
00432         kmo_init_fits_desc(&desc_lcal);
00433 
00434         /* --- check input --- */
00435         KMO_TRY_ASSURE((parlist != NULL) &&
00436                        (frameset != NULL),
00437                        CPL_ERROR_NULL_INPUT,
00438                        "Not all input data is provided!");
00439 
00440         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, FLAT_SKY) >= 1,
00441                        CPL_ERROR_ILLEGAL_INPUT,
00442                        "One or more FLAT_SKY frames are required!");
00443 
00444         if (cpl_frameset_count_tags(frameset, FLAT_SKY) < 3) {
00445             cpl_msg_warning(cpl_func, "It is recommended to provide at least "
00446                                       "3 FLAT_SKY frames!");
00447         }
00448 
00449         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, MASTER_DARK) == 1,
00450                        CPL_ERROR_ILLEGAL_INPUT,
00451                        "Exactly one MASTER_DARK frame is required!");
00452 
00453         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, MASTER_FLAT) == 1,
00454                        CPL_ERROR_ILLEGAL_INPUT,
00455                        "Exactly one MASTER_FLAT frame is required!");
00456 
00457         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00458                        CPL_ERROR_ILLEGAL_INPUT,
00459                        "Exactly one XCAL frame is required!");
00460 
00461         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00462                        CPL_ERROR_ILLEGAL_INPUT,
00463                        "Exactly one YCAL frame is required!");
00464 
00465         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00466                        CPL_ERROR_ILLEGAL_INPUT,
00467                        "Exactly one LCAL frame is required!");
00468 
00469         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00470                        CPL_ERROR_ILLEGAL_INPUT,
00471                        "Exactly one WAVE_BAND frame is required!");
00472 
00473         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_illumination") == 1,
00474                        CPL_ERROR_ILLEGAL_INPUT,
00475                        "Cannot identify RAW and CALIB frames!");
00476 
00477         /* --- get parameters --- */
00478         cpl_msg_info("", "--- Parameter setup for kmo_illumination ---");
00479 
00480         KMO_TRY_EXIT_IF_NULL(
00481             method = kmo_dfs_get_parameter_string(parlist,
00482                                               "kmos.kmo_illumination.imethod"));
00483 
00484         KMO_TRY_ASSURE((strcmp(method, "NN") == 0) ||
00485                        (strcmp(method, "lwNN") == 0) ||
00486                        (strcmp(method, "swNN") == 0) ||
00487                        (strcmp(method, "MS") == 0) ||
00488                        (strcmp(method, "CS") == 0),
00489                        CPL_ERROR_ILLEGAL_INPUT,
00490                        "method must be either \"NN\", \"lwNN\", "
00491                        "\"swNN\", \"MS\" or \"CS\"!");
00492 
00493         KMO_TRY_EXIT_IF_ERROR(
00494             kmo_dfs_print_parameter_help(parlist,
00495                                         "kmos.kmo_illumination.imethod"));
00496 
00497         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00498                 "kmos.kmo_illumination.neighborhoodRange");
00499         KMO_TRY_CHECK_ERROR_STATE();
00500 
00501         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00502                 CPL_ERROR_ILLEGAL_INPUT,
00503                 "neighborhoodRange must be greater than 0.0");
00504 
00505         KMO_TRY_EXIT_IF_ERROR(
00506             kmo_dfs_print_parameter_help(parlist,
00507                                     "kmos.kmo_illumination.neighborhoodRange"));
00508 
00509         ranges_txt = kmo_dfs_get_parameter_string(parlist,
00510                                                   "kmos.kmo_illumination.range");
00511         KMO_TRY_CHECK_ERROR_STATE();
00512 
00513         KMO_TRY_EXIT_IF_ERROR(
00514             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_illumination.range"));
00515 
00516         ranges = kmo_identify_ranges(ranges_txt);
00517         KMO_TRY_CHECK_ERROR_STATE();
00518 
00519         flux = kmo_dfs_get_parameter_bool(parlist,
00520                                           "kmos.kmo_illumination.flux");
00521 
00522         KMO_TRY_ASSURE((flux == 0) ||
00523                        (flux == 1),
00524                        CPL_ERROR_ILLEGAL_INPUT,
00525                        "flux must be either FALSE or TRUE!");
00526 
00527         KMO_TRY_EXIT_IF_ERROR(
00528             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_illumination.flux"));
00529 
00530         kmo_band_pars_load(parlist, "kmos.kmo_illumination");
00531 
00532         KMO_TRY_EXIT_IF_ERROR(
00533             kmo_combine_pars_load(parlist,
00534                                   "kmos.kmo_illumination",
00535                                   &cmethod,
00536                                   &cpos_rej,
00537                                   &cneg_rej,
00538                                   &citer,
00539                                   &cmin,
00540                                   &cmax,
00541                                   FALSE));
00542         cpl_msg_info("", "-------------------------------------------");
00543 
00544         // check if filter_id, grating_id and rotator offset match for all
00545         // detectors
00546         KMO_TRY_EXIT_IF_ERROR(
00547             kmo_check_frameset_setup(frameset, FLAT_SKY,
00548                                        TRUE, FALSE, TRUE));
00549         KMO_TRY_EXIT_IF_ERROR(
00550             kmo_check_frame_setup(frameset, FLAT_SKY, XCAL,
00551                                        TRUE, FALSE, TRUE));
00552         KMO_TRY_EXIT_IF_ERROR(
00553             kmo_check_frame_setup(frameset, XCAL, YCAL,
00554                                        TRUE, FALSE, TRUE));
00555         KMO_TRY_EXIT_IF_ERROR(
00556             kmo_check_frame_setup(frameset, XCAL, LCAL,
00557                                        TRUE, FALSE, TRUE));
00558 
00559 //        KMO_TRY_EXIT_IF_ERROR(
00560 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00561 //        KMO_TRY_EXIT_IF_ERROR(
00562 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00563         // not tested, since MASTER_DARK needn't any particaular filter/grating
00564 //        KMO_TRY_EXIT_IF_ERROR(
00565 //            kmo_priv_check_frame_setup(frameset, XCAL, MASTER_DARK,
00566 //                                       TRUE, TRUE, TRUE,
00567 //                                       NULL));
00568         KMO_TRY_EXIT_IF_ERROR(
00569             kmo_check_frame_setup(frameset, XCAL, MASTER_FLAT,
00570                                        TRUE, FALSE, TRUE));
00571         KMO_TRY_EXIT_IF_ERROR(
00572             kmo_check_frame_setup(frameset, XCAL, BADPIXEL_FLAT,
00573                                        TRUE, FALSE, TRUE));
00574 
00575         KMO_TRY_EXIT_IF_NULL(
00576             frame = kmo_dfs_get_frame(frameset, XCAL));
00577         KMO_TRY_EXIT_IF_NULL(
00578             suffix = kmo_dfs_get_suffix(frame, TRUE, FALSE));
00579 
00580         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00581         cpl_msg_info("", "(grating 1, 2 & 3)");
00582 
00583         // check which IFUs are active for all frames
00584         KMO_TRY_EXIT_IF_NULL(
00585             unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0));
00586 
00587         KMO_TRY_EXIT_IF_NULL(
00588             unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before));
00589 
00590         kmo_print_unused_ifus(unused_ifus_before, FALSE);
00591 
00592         // load desc for MASTER_DARK and check
00593         KMO_TRY_EXIT_IF_NULL(
00594             frame = kmo_dfs_get_frame(frameset, MASTER_DARK));
00595         desc_dark = kmo_identify_fits_header(
00596                     cpl_frame_get_filename(frame));
00597         KMO_TRY_CHECK_ERROR_STATE_MSG("MASTER_DARK frame doesn't seem to "
00598                                       "be in KMOS-format!");
00599         KMO_TRY_ASSURE((desc_dark.nr_ext == 6) &&
00600                        (desc_dark.ex_badpix == FALSE) &&
00601                        (desc_dark.fits_type == f2d_fits) &&
00602                        (desc_dark.frame_type == detector_frame),
00603                        CPL_ERROR_ILLEGAL_INPUT,
00604                        "MASTER_DARK isn't in the correct format!!!");
00605         nx = desc_dark.naxis1;
00606         ny = desc_dark.naxis2;
00607 
00608         // load desc for MASTER_FLAT and check
00609         KMO_TRY_EXIT_IF_NULL(
00610             frame = kmo_dfs_get_frame(frameset, MASTER_FLAT));
00611         desc_flat = kmo_identify_fits_header(cpl_frame_get_filename(frame));
00612         KMO_TRY_CHECK_ERROR_STATE_MSG("MASTER_FLAT frame doesn't seem to "
00613                                       "be in KMOS-format!");
00614         KMO_TRY_ASSURE((desc_flat.nr_ext % 6 == 0) &&
00615                        (desc_flat.ex_badpix == FALSE) &&
00616                        (desc_flat.fits_type == f2d_fits) &&
00617                        (desc_flat.frame_type == detector_frame),
00618                        CPL_ERROR_ILLEGAL_INPUT,
00619                        "MASTER_FLAT isn't in the correct format!!!");
00620 
00621         // load desc for XCAL and check
00622         KMO_TRY_EXIT_IF_NULL(
00623             xcalFrame = kmo_dfs_get_frame(frameset, XCAL));
00624         desc_xcal = kmo_identify_fits_header(cpl_frame_get_filename(xcalFrame));
00625         KMO_TRY_CHECK_ERROR_STATE_MSG("XCAL frame doesn't seem to "
00626                                       "be in KMOS-format!");
00627         KMO_TRY_ASSURE((desc_xcal.nr_ext % 3 == 0) &&
00628                        (desc_xcal.ex_badpix == FALSE) &&
00629                        (desc_xcal.fits_type == f2d_fits) &&
00630                        (desc_xcal.frame_type == detector_frame),
00631                        CPL_ERROR_ILLEGAL_INPUT,
00632                        "XCAL isn't in the correct format!!!");
00633         KMO_TRY_ASSURE((desc_xcal.naxis1 == nx) &&
00634                        (desc_xcal.naxis2 == ny),
00635                        CPL_ERROR_ILLEGAL_INPUT,
00636                        "MASTER_DARK and XCAL frame haven't same dimensions! "
00637                        "(x,y): (%d,%d) vs (%d,%d)",
00638                        nx, ny, desc_xcal.naxis1, desc_xcal.naxis2);
00639 
00640         nr_devices = desc_xcal.nr_ext;
00641 
00642         // load desc for YCAL and check
00643         KMO_TRY_EXIT_IF_NULL(
00644             ycalFrame = kmo_dfs_get_frame(frameset, YCAL));
00645         desc_ycal = kmo_identify_fits_header(cpl_frame_get_filename(ycalFrame));
00646         KMO_TRY_CHECK_ERROR_STATE_MSG("YCAL frame doesn't seem to "
00647                                       "be in KMOS-format!");
00648         KMO_TRY_ASSURE((desc_ycal.nr_ext % 3 == 0) &&
00649                        (desc_ycal.ex_badpix == FALSE) &&
00650                        (desc_ycal.fits_type == f2d_fits) &&
00651                        (desc_ycal.frame_type == detector_frame),
00652                        CPL_ERROR_ILLEGAL_INPUT,
00653                        "YCAL isn't in the correct format!!!");
00654         KMO_TRY_ASSURE((desc_ycal.naxis1 == nx) &&
00655                        (desc_ycal.naxis2 == ny) &&
00656                        (desc_ycal.nr_ext == nr_devices),
00657                        CPL_ERROR_ILLEGAL_INPUT,
00658                        "MASTER_DARK and YCAL frame haven't same dimensions! "
00659                        "(x,y): (%d,%d) vs (%d,%d)",
00660                        nx, ny, desc_ycal.naxis1, desc_ycal.naxis2);
00661 
00662         // load desc for LCAL and check
00663         KMO_TRY_EXIT_IF_NULL(
00664             lcalFrame = kmo_dfs_get_frame(frameset, LCAL));
00665         desc_lcal = kmo_identify_fits_header(cpl_frame_get_filename(lcalFrame));
00666         KMO_TRY_CHECK_ERROR_STATE_MSG("LCAL frame doesn't seem to "
00667                                       "be in KMOS-format!");
00668         KMO_TRY_ASSURE((desc_lcal.nr_ext % 3 == 0) &&
00669                        (desc_lcal.ex_badpix == FALSE) &&
00670                        (desc_lcal.fits_type == f2d_fits) &&
00671                        (desc_lcal.frame_type == detector_frame),
00672                        CPL_ERROR_ILLEGAL_INPUT,
00673                        "LCAL isn't in the correct format!!!");
00674         KMO_TRY_ASSURE((desc_lcal.naxis1 == nx) &&
00675                        (desc_lcal.naxis2 == ny) &&
00676                        (desc_lcal.nr_ext == nr_devices),
00677                        CPL_ERROR_ILLEGAL_INPUT,
00678                        "MASTER_DARK and LCAL frame haven't same dimensions! "
00679                        "(x,y): (%d,%d) vs (%d,%d)",
00680                        nx, ny, desc_lcal.naxis1, desc_lcal.naxis2);
00681         KMO_TRY_EXIT_IF_NULL(
00682             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00683 
00684         // load desc for FLAT_SKY and check
00685         i = 1;
00686         nr_devices = KMOS_NR_DETECTORS;
00687         KMO_TRY_EXIT_IF_NULL(
00688             frame = kmo_dfs_get_frame(frameset, FLAT_SKY));
00689 
00690         KMO_TRY_EXIT_IF_NULL(
00691             main_header = kmclipm_propertylist_load(
00692                                          cpl_frame_get_filename(frame), 0));
00693         rotangle = cpl_propertylist_get_double(main_header, ROTANGLE);
00694         KMO_TRY_CHECK_ERROR_STATE_MSG("Cannot retrieve ROTANGLE FITS keyword from sky frame!");
00695         kmclipm_strip_angle(&rotangle);
00696         cpl_propertylist_delete(main_header); main_header = NULL;
00697 
00698         while (frame != NULL) {
00699             KMO_TRY_EXIT_IF_NULL(
00700                 main_header = kmclipm_propertylist_load(
00701                                              cpl_frame_get_filename(frame), 0));
00702 
00703             desc_sky = kmo_identify_fits_header(
00704                         cpl_frame_get_filename(frame));
00705             KMO_TRY_CHECK_ERROR_STATE_MSG("FLAT_SKY frame doesn't seem to "
00706                                           "be in KMOS-format!");
00707             KMO_TRY_ASSURE((desc_sky.nr_ext == 3) &&
00708                            (desc_sky.ex_badpix == FALSE) &&
00709                            (desc_sky.fits_type == raw_fits) &&
00710                            (desc_sky.frame_type == detector_frame),
00711                            CPL_ERROR_ILLEGAL_INPUT,
00712                            "FLAT_SKY isn't in the correct format!!!");
00713             KMO_TRY_ASSURE((desc_sky.naxis1 == nx) &&
00714                            (desc_sky.naxis2 == ny) &&
00715                            (desc_sky.nr_ext == nr_devices),
00716                            CPL_ERROR_ILLEGAL_INPUT,
00717                            "MASTER_DARK and FLAT_SKY (no. %d) frame haven't "
00718                            "same dimensions! (x,y): (%d,%d) vs (%d,%d)",
00719                            i, nx, ny, desc_flat.naxis1, desc_flat.naxis2);
00720             kmo_free_fits_desc(&desc_sky);
00721             kmo_init_fits_desc(&desc_sky);
00722 
00723             KMO_TRY_ASSURE(
00724                 (kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) &&
00725                 (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE) &&
00726                 (kmo_check_lamp(main_header, INS_LAMP3_ST) == FALSE) &&
00727                 (kmo_check_lamp(main_header, INS_LAMP4_ST) == FALSE),
00728                 CPL_ERROR_ILLEGAL_INPUT,
00729                 "All lamps must be switched off for the FLAT_SKY frames!");
00730 
00731             // assert that filters have correct IDs and that all detectors of
00732             // all input frames have the same filter set
00733             for (i = 1; i <= 3; i++) {
00734                 // ESO INS FILTi ID
00735                 KMO_TRY_EXIT_IF_NULL(
00736                     keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i,
00737                                           IFU_FILTID_POSTFIX));
00738                 KMO_TRY_EXIT_IF_NULL(
00739                     filter_id = cpl_propertylist_get_string(main_header,
00740                                                             keyword));
00741 
00742                 KMO_TRY_EXIT_IF_NULL(
00743                     filter_id_l = cpl_propertylist_get_string(tmp_header,
00744                                                               keyword));
00745                 cpl_free(keyword); keyword = NULL;
00746 
00747                 KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00748                                (strcmp(filter_id, "YJ") == 0) ||
00749                                (strcmp(filter_id, "H") == 0) ||
00750                                (strcmp(filter_id, "K") == 0) ||
00751                                (strcmp(filter_id, "HK") == 0),
00752                                CPL_ERROR_ILLEGAL_INPUT,
00753                                "Filter ID in primary header must be either 'IZ', "
00754                                "'YJ', 'H', 'K' or " "'HK' !");
00755 
00756                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_l) == 0,
00757                                CPL_ERROR_ILLEGAL_INPUT,
00758                                "Filter IDs must be the same for FLAT_SKY frame"
00759                                " and lcal frame!"
00760                                "Detector No.: %d\n%s: %s\nLCAL: %s\n",
00761                                i, cpl_frame_get_filename(frame),
00762                                filter_id, filter_id_l);
00763 
00764                 // ESO INS GRATi ID
00765                 KMO_TRY_EXIT_IF_NULL(
00766                     keyword = cpl_sprintf("%s%d%s", IFU_GRATID_PREFIX, i,
00767                                           IFU_GRATID_POSTFIX));
00768                 KMO_TRY_EXIT_IF_NULL(
00769                     filter_id = cpl_propertylist_get_string(main_header,
00770                                                             keyword));
00771 
00772                 KMO_TRY_EXIT_IF_NULL(
00773                     filter_id_l = cpl_propertylist_get_string(tmp_header,
00774                                                               keyword));
00775                 cpl_free(keyword); keyword = NULL;
00776 
00777                 KMO_TRY_ASSURE((strcmp(filter_id, "IZ") == 0) ||
00778                                (strcmp(filter_id, "YJ") == 0) ||
00779                                (strcmp(filter_id, "H") == 0) ||
00780                                (strcmp(filter_id, "K") == 0) ||
00781                                (strcmp(filter_id, "HK") == 0),
00782                                CPL_ERROR_ILLEGAL_INPUT,
00783                                "Grating ID in primary header must be either "
00784                                "'IZ', 'YJ', 'H', 'K' or " "'HK' !");
00785 
00786                 KMO_TRY_ASSURE(strcmp(filter_id, filter_id_l) == 0,
00787                                CPL_ERROR_ILLEGAL_INPUT,
00788                                "Grating IDs must be the same for FLAT_SKY frame"
00789                                " and lcal frame!"
00790                                "Detector No.: %d\n%s: %s\nLCAL: %s\n",
00791                                i, cpl_frame_get_filename(frame),
00792                                filter_id, filter_id_l);
00793 
00794                 tmp_rotangle = cpl_propertylist_get_double(main_header, ROTANGLE);
00795                 KMO_TRY_CHECK_ERROR_STATE_MSG("Cannot retrieve ROTANGLE FITS keyword from sky frame!");
00796                 kmclipm_strip_angle(&tmp_rotangle);
00797                 KMO_TRY_ASSURE((abs(rotangle - tmp_rotangle) < 10.0) ||
00798                                (abs(rotangle - tmp_rotangle) > 360.-10.) ,
00799                         CPL_ERROR_ILLEGAL_INPUT,
00800                         "OCS ROT NAANGLE of sky flat frames differ to much: %f %f",
00801                         rotangle, tmp_rotangle);
00802             }
00803             cpl_propertylist_delete(main_header); main_header = NULL;
00804 
00805             // get next FLAT_SKY frame
00806             frame = kmo_dfs_get_frame(frameset, NULL);
00807             KMO_TRY_CHECK_ERROR_STATE();
00808             i++;
00809         }
00810 
00811         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00812 
00813         KMO_TRY_EXIT_IF_NULL(
00814             frame = kmo_dfs_get_frame(frameset, FLAT_SKY));
00815         KMO_TRY_EXIT_IF_NULL(
00816             main_header = kmo_dfs_load_primary_header(frameset, FLAT_SKY));
00817 
00818         //
00819         // noise will be propagated when:
00820         // MASTER_DARK and MASTER_FLAT have noise extensions and if at least
00821         // 2 FLAT_SKY frames are provided.
00822         // Otherwise noise will be ignored.
00823         //
00824         if (desc_dark.ex_noise &&
00825             desc_flat.ex_noise &&
00826             (cpl_frameset_count_tags(frameset, FLAT_SKY) >= 2)) {
00827             process_noise = TRUE;
00828         }
00829 
00830         if (cpl_frameset_count_tags(frameset, FLAT_SKY) == 1) {
00831             cpl_msg_warning(cpl_func, "cmethod is changed to 'average' "
00832                             "since there is only one input frame! (The output "
00833                             "file won't have any noise extensions)");
00834 
00835             cmethod = "average";
00836         }
00837 
00838         // setup grid definition, wavekength start and end points will be set
00839         // in the detector loop
00840         KMO_TRY_EXIT_IF_ERROR(
00841             kmclipm_setup_grid(&gd, method, neighborhoodRange));
00842 
00843         // create filename for LUT
00844         KMO_TRY_EXIT_IF_NULL(
00845             fn_lut = cpl_sprintf("%s%s", "lut", suffix));
00846 
00847         // extract bounds
00848         KMO_TRY_EXIT_IF_NULL(
00849             tmp_header = kmclipm_propertylist_load(
00850                                          cpl_frame_get_filename(xcalFrame), 0));
00851         KMO_TRY_EXIT_IF_NULL(
00852             bounds = kmclipm_extract_bounds(tmp_header));
00853         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00854 
00855         // get timestamps of xcal, ycal & lcal
00856         KMO_TRY_EXIT_IF_NULL(
00857             calTimestamp = kmo_get_timestamps(xcalFrame, ycalFrame, lcalFrame));
00858 
00859         // create arrays to hold reconstructed data and noise cubes and
00860         // their headers
00861         KMO_TRY_EXIT_IF_NULL(
00862             stored_data_cubes =
00863                             (cpl_imagelist**)cpl_malloc(nr_devices *
00864                                                     KMOS_IFUS_PER_DETECTOR *
00865                                                     sizeof(cpl_imagelist*)));
00866         KMO_TRY_EXIT_IF_NULL(
00867             stored_noise_cubes =
00868                             (cpl_imagelist**)cpl_malloc(nr_devices *
00869                                                     KMOS_IFUS_PER_DETECTOR *
00870                                                     sizeof(cpl_imagelist*)));
00871         KMO_TRY_EXIT_IF_NULL(
00872             stored_data_images =
00873                             (cpl_image**)cpl_malloc(nr_devices *
00874                                                     KMOS_IFUS_PER_DETECTOR *
00875                                                     sizeof(cpl_image*)));
00876         KMO_TRY_EXIT_IF_NULL(
00877             stored_noise_images =
00878                             (cpl_image**)cpl_malloc(nr_devices *
00879                                                     KMOS_IFUS_PER_DETECTOR *
00880                                                     sizeof(cpl_image*)));
00881         KMO_TRY_EXIT_IF_NULL(
00882             stored_sub_data_headers =
00883                             (cpl_propertylist**)cpl_malloc(nr_devices *
00884                                                     KMOS_IFUS_PER_DETECTOR *
00885                                                     sizeof(cpl_propertylist*)));
00886         KMO_TRY_EXIT_IF_NULL(
00887             stored_sub_noise_headers =
00888                             (cpl_propertylist**)cpl_malloc(nr_devices *
00889                                                     KMOS_IFUS_PER_DETECTOR *
00890                                                     sizeof(cpl_propertylist*)));
00891 
00892         for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
00893             stored_data_cubes[i] = NULL;
00894             stored_noise_cubes[i] = NULL;
00895             stored_data_images[i] = NULL;
00896             stored_noise_images[i] = NULL;
00897             stored_sub_data_headers[i] = NULL;
00898             stored_sub_noise_headers[i] = NULL;
00899         }
00900 
00901         //
00902         // loop through all detectors
00903         //
00904         for (det_nr = 1; det_nr <= nr_devices; det_nr++) {
00905             cpl_msg_info("","Processing detector No. %d", det_nr);
00906 
00907             KMO_TRY_EXIT_IF_NULL(
00908                 detector_in = cpl_imagelist_new());
00909 
00910             // load data of device i of all FLAT_SKY frames into an imagelist
00911             KMO_TRY_EXIT_IF_NULL(
00912                 img_in = kmo_dfs_load_image(frameset, FLAT_SKY, det_nr, FALSE, TRUE, NULL));
00913 
00914             i = 0;
00915             while (img_in != NULL) {
00916                 cpl_imagelist_set(detector_in, img_in, i);
00917                 KMO_TRY_CHECK_ERROR_STATE();
00918 
00919                 /* load same extension of next FLAT_SKY frame*/
00920                 img_in = kmo_dfs_load_image(frameset, NULL, det_nr, FALSE, TRUE, NULL);
00921                 KMO_TRY_CHECK_ERROR_STATE();
00922 
00923                 i++;
00924             }
00925 
00926             //
00927             // process imagelist
00928             //
00929 
00930             // combine imagelist (data only) and create noise (stdev of data)
00931             cpl_msg_info("","Combining frames...");
00932             if (process_noise) {
00933                 KMO_TRY_EXIT_IF_ERROR(
00934                     kmclipm_combine_frames(detector_in,
00935                                            NULL,
00936                                            NULL,
00937                                            cmethod,
00938                                            cpos_rej,
00939                                            cneg_rej,
00940                                            citer,
00941                                            cmax,
00942                                            cmin,
00943                                            &combined_data,
00944                                            &combined_noise,
00945                                            -1.0));
00946             } else {
00947                 KMO_TRY_EXIT_IF_ERROR(
00948                     kmclipm_combine_frames(detector_in,
00949                                            NULL,
00950                                            NULL,
00951                                            cmethod,
00952                                            cpos_rej,
00953                                            cneg_rej,
00954                                            citer,
00955                                            cmax,
00956                                            cmin,
00957                                            &combined_data,
00958                                            NULL,
00959                                            -1.0));
00960             }
00961 
00962             if (kmclipm_omit_warning_one_slice > 10) {
00963                 cpl_msg_warning(cpl_func, "Previous warning (number of "
00964                                           "identified slices) occured %d times.",
00965                                 kmclipm_omit_warning_one_slice);
00966                 kmclipm_omit_warning_one_slice = FALSE;
00967             }
00968 
00969             cpl_imagelist_delete(detector_in); detector_in = NULL;
00970 
00971             //
00972             // reconstruct
00973             //
00974 
00975             // load MASTER_DARK and MASTER_FLAT
00976             KMO_TRY_EXIT_IF_NULL(
00977                 img_dark = kmo_dfs_load_image(frameset, MASTER_DARK,
00978                                               det_nr, FALSE, FALSE, NULL));
00979 
00980             if (process_noise) {
00981                 KMO_TRY_EXIT_IF_NULL(
00982                     img_dark_noise = kmo_dfs_load_image(frameset, MASTER_DARK,
00983                                                         det_nr, TRUE, FALSE, NULL));
00984             }
00985 
00986             KMO_TRY_EXIT_IF_NULL(
00987                 img_flat = kmo_dfs_load_cal_image(frameset, MASTER_FLAT,
00988                         det_nr, FALSE, rotangle, FALSE, NULL, &rotangle_found));
00989 
00990             if (process_noise) {
00991                 KMO_TRY_EXIT_IF_NULL(
00992                     img_flat_noise = kmo_dfs_load_cal_image(frameset, MASTER_FLAT,
00993                             det_nr, TRUE, rotangle, FALSE, NULL, &rotangle_found));
00994             }
00995 
00996             // load calibration files
00997            KMO_TRY_EXIT_IF_NULL(
00998                 xcal = kmo_dfs_load_cal_image(frameset, XCAL, det_nr, FALSE, rotangle,
00999                         FALSE, NULL, &rotangle_found));
01000             KMO_TRY_EXIT_IF_NULL(
01001                 ycal = kmo_dfs_load_cal_image(frameset, YCAL, det_nr, FALSE, rotangle,
01002                         FALSE, NULL, &rotangle_found));
01003             KMO_TRY_EXIT_IF_NULL(
01004                 lcal = kmo_dfs_load_cal_image(frameset, LCAL, det_nr, FALSE, rotangle,
01005                         FALSE, NULL, &rotangle_found));
01006 
01007             char *tmp_band_method = getenv("KMO_BAND_METHOD");
01008             int band_method = 0;
01009             if (tmp_band_method != NULL) {
01010                 band_method = atoi(tmp_band_method);
01011             }
01012 
01013             // ESO INS FILTi ID
01014             KMO_TRY_EXIT_IF_NULL(
01015                 keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, det_nr,
01016                                       IFU_FILTID_POSTFIX));
01017             KMO_TRY_EXIT_IF_NULL(
01018                 filter_id = cpl_propertylist_get_string(main_header, keyword));
01019             cpl_free(keyword); keyword = NULL;
01020 
01021             KMO_TRY_EXIT_IF_NULL(
01022                 band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
01023             KMO_TRY_EXIT_IF_ERROR(
01024                 kmclipm_setup_grid_band_lcal(&gd, lcal, filter_id, band_method,
01025                                              band_table));
01026             cpl_table_delete(band_table); band_table = NULL;
01027 
01028             cpl_msg_info("","Reconstructing cubes...");
01029             for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
01030                 // update sub-header
01031                 ifu_nr = (det_nr-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
01032 
01033                 // load raw image and sub-header
01034                 KMO_TRY_EXIT_IF_NULL(
01035                     sub_header = kmo_dfs_load_sub_header(frameset, FLAT_SKY,
01036                                                          det_nr, FALSE));
01037 
01038                 KMO_TRY_EXIT_IF_NULL(
01039                     punused_ifus = cpl_array_get_data_int_const(
01040                                                   unused_ifus_after[det_nr-1]));
01041 
01042                 // check if IFU is valid according to main header keywords &
01043                 // calibration files
01044                 KMO_TRY_EXIT_IF_NULL(
01045                     keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr,
01046                                           IFU_VALID_POSTFIX));
01047                 KMO_TRY_CHECK_ERROR_STATE();
01048                 ranges_txt = cpl_propertylist_get_string(main_header, keyword);
01049                 cpl_free(keyword); keyword = NULL;
01050 
01051                 if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
01052                     (bounds[2*(ifu_nr-1)] != -1) &&
01053                     (bounds[2*(ifu_nr-1)+1] != -1) &&
01054                     (punused_ifus[j] == 0))
01055                 {
01056                     // IFU is valid
01057                     cpl_error_reset();
01058 
01059                     // calculate WCS
01060                     KMO_TRY_EXIT_IF_ERROR(
01061                         kmo_calc_wcs(main_header, sub_header, ifu_nr,
01062                                      gd.l.start, gd.l.delta));
01063 
01064                     // reconstruct data
01065                     KMO_TRY_EXIT_IF_ERROR(
01066                         kmo_reconstruct_sci_image(ifu_nr,
01067                                                 bounds[2*(ifu_nr-1)],
01068                                                 bounds[2*(ifu_nr-1)+1],
01069                                                 combined_data,
01070                                                 combined_noise,
01071                                                 img_dark,
01072                                                 img_dark_noise,
01073                                                 img_flat,
01074                                                 img_flat_noise,
01075                                                 xcal,
01076                                                 ycal,
01077                                                 lcal,
01078                                                 &gd,
01079                                                 calTimestamp,
01080                                                 fn_lut,
01081                                                 &cube_data,
01082                                                 &cube_noise,
01083                                                 flux));
01084                     KMO_TRY_CHECK_ERROR_STATE();
01085                 } else {
01086                     // IFU is invalid
01087                     cpl_error_reset();
01088                 } // if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) ...
01089 
01090                 // save output
01091                 KMO_TRY_EXIT_IF_NULL(
01092                     extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA));
01093 
01094                 KMO_TRY_EXIT_IF_ERROR(
01095                     kmclipm_update_property_string(sub_header, EXTNAME,
01096                                                    extname,
01097                                                    "FITS extension name"));
01098 
01099                 cpl_free(extname); extname = NULL;
01100 
01101                 // store cube and sub header into array for later
01102                 stored_data_cubes[ifu_nr - 1] = cube_data;
01103                 stored_sub_data_headers[ifu_nr - 1] = sub_header;
01104 
01105                 if (process_noise) {
01106                     KMO_TRY_EXIT_IF_NULL(
01107                         sub_header = cpl_propertylist_duplicate(
01108                                            stored_sub_data_headers[ifu_nr - 1]));
01109                     KMO_TRY_EXIT_IF_NULL(
01110                         extname = kmo_extname_creator(ifu_frame, ifu_nr,
01111                                                       EXT_NOISE));
01112 
01113                     KMO_TRY_EXIT_IF_ERROR(
01114                         kmclipm_update_property_string(sub_header,
01115                                                 EXTNAME,
01116                                                 extname,
01117                                                 "FITS extension name"));
01118 
01119                     cpl_free(extname); extname = NULL;
01120 
01121                     stored_noise_cubes[ifu_nr - 1] = cube_noise;
01122                     stored_sub_noise_headers[ifu_nr - 1] = sub_header;
01123                 }
01124                 cpl_image_delete(data_ifu); data_ifu = NULL;
01125                 cpl_image_delete(noise_ifu); noise_ifu = NULL;
01126                 cube_data = NULL;
01127                 cube_noise = NULL;
01128             } // for j IFUs
01129 
01130             // free memory
01131             cpl_image_delete(combined_data); combined_data = NULL;
01132             cpl_image_delete(combined_noise); combined_noise = NULL;
01133 
01134             cpl_image_delete(xcal); xcal = NULL;
01135             cpl_image_delete(ycal); ycal = NULL;
01136             cpl_image_delete(lcal); lcal = NULL;
01137 
01138             cpl_image_delete(img_dark); img_dark = NULL;
01139             cpl_image_delete(img_flat); img_flat = NULL;
01140             if (process_noise) {
01141                 cpl_image_delete(img_dark_noise); img_dark_noise = NULL;
01142                 cpl_image_delete(img_flat_noise); img_flat_noise = NULL;
01143             }
01144 
01145         } // for nr_devices
01146 
01147         // collapse cubes using rejection
01148         cpl_msg_info("","Collapsing cubes...");
01149         for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01150             if (ranges != NULL) {
01151                 ifu_crpix = cpl_propertylist_get_double(stored_sub_data_headers[i],
01152                                                         CRPIX3);
01153                 KMO_TRY_CHECK_ERROR_STATE_MSG(
01154                                "CRPIX3 keyword in FITS-header is missing!");
01155 
01156                 ifu_crval = cpl_propertylist_get_double(stored_sub_data_headers[i],
01157                                                         CRVAL3);
01158                 KMO_TRY_CHECK_ERROR_STATE_MSG(
01159                                "CRVAL3 keyword in FITS-header is missing!");
01160 
01161                 ifu_cdelt = cpl_propertylist_get_double(stored_sub_data_headers[i],
01162                                                         CDELT3);
01163                 KMO_TRY_CHECK_ERROR_STATE_MSG(
01164                                "CDELT3 keyword in FITS-header is missing!");
01165             }
01166 
01167             KMO_TRY_EXIT_IF_NULL(
01168                 identified_slices = kmo_identify_slices(ranges,
01169                                                         ifu_crpix,
01170                                                         ifu_crval,
01171                                                         ifu_cdelt,
01172                                                         gd.l.dim));
01173 
01174             if (stored_data_cubes[i] != NULL) {
01175                 KMO_TRY_EXIT_IF_ERROR(
01176                     kmclipm_make_image(stored_data_cubes[i],
01177                                        stored_noise_cubes[i],
01178                                        &stored_data_images[i],
01179                                        &stored_noise_images[i],
01180                                        identified_slices,
01181                                        cmethod, cpos_rej, cneg_rej,
01182                                        citer, cmax, cmin));
01183             }
01184             cpl_vector_delete(identified_slices); identified_slices = NULL;
01185         }
01186 
01187         // normalise all IFUs as a group.
01188         // Calculate mean of each IFU, add up and divide by number of successful
01189         // averaged IFUs.
01190         // Then divide all valid IFUs with mean value
01191         //
01192         count = 0;
01193         for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01194             if (stored_data_images[i] != NULL) {
01195                 KMO_TRY_ASSURE(cpl_image_count_rejected(stored_data_images[i]) <
01196                                cpl_image_get_size_x(stored_data_images[i])*
01197                                cpl_image_get_size_y(stored_data_images[i]),
01198                                CPL_ERROR_ILLEGAL_INPUT,
01199                                "The collapsed, dark-subtracted image contains "
01200                                "only invalid values! Probably the provided "
01201                                "FLAT_SKY frames are exactly the same as the "
01202                                "frames used for MASTER_DARK calculation.");
01203 
01204                 mean_data += cpl_image_get_mean(stored_data_images[i]);
01205                 KMO_TRY_CHECK_ERROR_STATE();
01206                 count++;
01207             }
01208 
01209         }
01210         mean_data /= count;
01211 
01212         if (mean_data != 0.0) {
01213             for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01214                 if (stored_data_images[i] != NULL) {
01215                     KMO_TRY_EXIT_IF_ERROR(
01216                         cpl_image_divide_scalar(stored_data_images[i],
01217                                                 mean_data));
01218                 }
01219             }
01220         } else {
01221             cpl_msg_warning(cpl_func, "Data couldn't be normalised "
01222                                       "(mean = 0.0)!");
01223         }
01224 
01225         if (process_noise) {
01226 //            count = 0;
01227 //            for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01228 //                if (stored_noise_images[i] != NULL) {
01229 //                    mean_noise += cpl_image_get_mean(stored_noise_images[i]);
01230 //                    KMO_TRY_CHECK_ERROR_STATE();
01231 //                    count++;
01232 //                }
01233 //            }
01234 //            mean_noise /= count;
01235 
01236             if (mean_data != 0.0) {
01237                 for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01238                     if (stored_noise_images[i] != NULL) {
01239                         KMO_TRY_EXIT_IF_ERROR(
01240                             cpl_image_divide_scalar(stored_noise_images[i],
01241                                                     mean_data));
01242                     }
01243                 }
01244             } else {
01245                 cpl_msg_warning(cpl_func, "Noise couldn't be normalised "
01246                                           "(mean = 0.0)!");
01247             }
01248         }
01249 
01250         // calculate qc parameters on normalised data
01251         qc_spat_unif = 0.0;
01252         count = 0;
01253         for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01254             if (stored_data_images[i] != NULL) {
01255                 tmp_mean = cpl_image_get_mean(stored_data_images[i]);
01256                 tmp_stdev = cpl_image_get_stdev (stored_data_images[i]);
01257 
01258                 qc_spat_unif += pow(tmp_mean-1, 2);
01259                 if (fabs(tmp_mean) > qc_max_dev) {
01260                     qc_max_dev = tmp_mean-1;
01261                     qc_max_dev_id = i+1;
01262                 }
01263                 if (fabs(tmp_stdev) > qc_max_nonunif) {
01264                     qc_max_nonunif = tmp_stdev;
01265                     qc_max_nonunif_id = i+1;
01266                 }
01267                 KMO_TRY_CHECK_ERROR_STATE();
01268                 count++;
01269             }
01270         }
01271         qc_spat_unif = sqrt(qc_spat_unif / count);
01272 
01273         //
01274         // save data
01275         //
01276 
01277         // update which IFUs are not used
01278         kmo_print_unused_ifus(unused_ifus_after, TRUE);
01279 
01280         KMO_TRY_EXIT_IF_ERROR(
01281             kmo_set_unused_ifus(unused_ifus_after, main_header,
01282                                 "kmo_illumination"));
01283 
01284         cpl_msg_info("","Saving data...");
01285 
01286         KMO_TRY_EXIT_IF_ERROR(
01287             kmclipm_update_property_double(main_header,
01288                                            QC_SPAT_UNIF,
01289                                            qc_spat_unif,
01290                               "[adu] uniformity of illumination correction"));
01291         KMO_TRY_EXIT_IF_ERROR(
01292             kmclipm_update_property_double(main_header,
01293                                           QC_SPAT_MAX_DEV,
01294                                           qc_max_dev,
01295                                           "[adu] max. deviation from unity"));
01296         KMO_TRY_EXIT_IF_ERROR(
01297             kmclipm_update_property_int(main_header,
01298                                     QC_SPAT_MAX_DEV_ID,
01299                                     qc_max_dev_id,
01300                                     "[] IFU ID with max. dev. from unity"));
01301         KMO_TRY_EXIT_IF_ERROR(
01302             kmclipm_update_property_double(main_header,
01303                                            QC_SPAT_MAX_NONUNIF,
01304                                            qc_max_nonunif,
01305                                    "[adu] max. stdev of illumination corr."));
01306         KMO_TRY_EXIT_IF_ERROR(
01307             kmclipm_update_property_int(main_header,
01308                                     QC_SPAT_MAX_NONUNIF_ID,
01309                                     qc_max_nonunif_id,
01310                                   "[] IFU ID with max. stdev in illum. corr."));
01311 
01312         KMO_TRY_EXIT_IF_ERROR(
01313             kmo_dfs_save_main_header(frameset, ILLUM_CORR, suffix, frame,
01314                                      main_header, parlist, cpl_func));
01315 
01316         for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01317             KMO_TRY_EXIT_IF_ERROR(
01318                 kmo_dfs_save_image(stored_data_images[i], ILLUM_CORR, suffix,
01319                                    stored_sub_data_headers[i], 0./0.));
01320 
01321             if (process_noise) {
01322                 KMO_TRY_EXIT_IF_ERROR(
01323                     kmo_dfs_save_image(stored_noise_images[i], ILLUM_CORR,
01324                                        suffix, stored_sub_noise_headers[i], 0./0.));
01325             }
01326         }
01327     }
01328     KMO_CATCH
01329     {
01330         KMO_CATCH_MSG();
01331         ret_val = -1;
01332     }
01333     kmo_free_fits_desc(&desc_sky);
01334     kmo_free_fits_desc(&desc_dark);
01335     kmo_free_fits_desc(&desc_flat);
01336     kmo_free_fits_desc(&desc_xcal);
01337     kmo_free_fits_desc(&desc_ycal);
01338     kmo_free_fits_desc(&desc_lcal);
01339     cpl_image_delete(combined_data); combined_data = NULL;
01340     cpl_image_delete(combined_noise); combined_noise = NULL;
01341     cpl_image_delete(xcal); xcal = NULL;
01342     cpl_image_delete(ycal); ycal = NULL;
01343     cpl_image_delete(lcal); lcal = NULL;
01344     cpl_image_delete(img_dark); img_dark = NULL;
01345     cpl_image_delete(img_dark_noise); img_dark_noise = NULL;
01346     cpl_image_delete(img_flat); img_flat = NULL;
01347     cpl_image_delete(img_flat_noise); img_flat_noise = NULL;
01348     cpl_array_delete(calTimestamp); calTimestamp = NULL;
01349     cpl_propertylist_delete(main_header); main_header = NULL;
01350     cpl_free(bounds); bounds = NULL;
01351 
01352     for (i = 0; i < nr_devices * KMOS_IFUS_PER_DETECTOR; i++) {
01353         if (stored_data_cubes != NULL) {
01354             cpl_imagelist_delete(stored_data_cubes[i]);
01355             stored_data_cubes[i] = NULL;
01356         }
01357 
01358         if (stored_noise_cubes != NULL) {
01359             cpl_imagelist_delete(stored_noise_cubes[i]);
01360             stored_noise_cubes[i] = NULL;
01361         }
01362 
01363         if (stored_data_images != NULL) {
01364             cpl_image_delete(stored_data_images[i]);
01365             stored_data_images[i] = NULL;
01366         }
01367 
01368         if (stored_noise_images != NULL) {
01369             cpl_image_delete(stored_noise_images[i]);
01370             stored_noise_images[i] = NULL;
01371         }
01372 
01373         if (stored_sub_data_headers != NULL) {
01374             cpl_propertylist_delete(stored_sub_data_headers[i]);
01375             stored_sub_data_headers[i] = NULL;
01376         }
01377 
01378         if (stored_sub_noise_headers != NULL) {
01379             cpl_propertylist_delete(stored_sub_noise_headers[i]);
01380             stored_sub_noise_headers[i] = NULL;
01381         }
01382     }
01383 
01384     kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL;
01385     kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL;
01386     cpl_free(stored_data_cubes); stored_data_cubes = NULL;
01387     cpl_free(stored_noise_cubes); stored_noise_cubes = NULL;
01388     cpl_free(stored_data_images); stored_data_images = NULL;
01389     cpl_free(stored_noise_images); stored_noise_images = NULL;
01390     cpl_free(stored_sub_data_headers); stored_sub_data_headers = NULL;
01391     cpl_free(stored_sub_noise_headers); stored_sub_noise_headers = NULL;
01392     cpl_free(fn_lut); fn_lut = NULL;
01393     cpl_free(suffix); suffix = NULL;
01394 
01395     return ret_val;
01396 }
01397