KMOS Pipeline Reference Manual  1.0.7
kmo_wave_cal.c
00001 /* $Id: kmo_wave_cal.c,v 1.40 2013/01/24 03:36:40 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/01/24 03:36:40 $
00024  * $Revision: 1.40 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 #include <string.h>
00036 #include <math.h>
00037 
00038 #ifdef __USE_XOPEN2K
00039 #include <stdlib.h>
00040 #define GGG
00041 #else
00042 #define __USE_XOPEN2K /* to get the definition for setenv in stdlib.h */
00043 #include <stdlib.h>
00044 #undef __USE_XOPEN2K
00045 #endif
00046 
00047 #include <cpl.h>
00048 
00049 #include "kmo_utils.h"
00050 #include "kmo_functions.h"
00051 #include "kmo_priv_wave_cal.h"
00052 #include "kmo_priv_functions.h"
00053 #include "kmo_cpl_extensions.h"
00054 #include "kmo_dfs.h"
00055 #include "kmo_error.h"
00056 #include "kmo_constants.h"
00057 #include "kmo_debug.h"
00058 
00059 /*-----------------------------------------------------------------------------
00060  *                          Functions prototypes
00061  *----------------------------------------------------------------------------*/
00062 
00063 static int kmo_wave_cal_create(cpl_plugin *);
00064 static int kmo_wave_cal_exec(cpl_plugin *);
00065 static int kmo_wave_cal_destroy(cpl_plugin *);
00066 static int kmo_wave_cal(cpl_parameterlist *, cpl_frameset *);
00067 
00068 /*-----------------------------------------------------------------------------
00069  *                          Static variables
00070  *----------------------------------------------------------------------------*/
00071 
00072 static char kmo_wave_cal_description[] =
00073 "This recipe creates the wavelength calibration frame needed for all three\n"
00074 "detectors. It must be called after the kmo_flat recipe, which generates the\n"
00075 "two spatial calibration frames needed in this recipe. As input a lamp-on frame,\n"
00076 "a lamp-off frame, the flat badpixel frame, the spatial calibration frames and\n"
00077 "the list with the reference arclines are required."
00078 "An additional output frame is the resampled image of the reconstructed arc\n"
00079 "frame. 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 calibration was\n"
00081 "successful.\n"
00082 "The lists of reference arclines are supposed to contain the lines for both\n"
00083 "available calibration arc-lamps, i.e. Argon and Neon. The list is supposed to\n"
00084 "be a F2L KMOS FITS file with three columns:\n"
00085 "1. Reference wavelength\n"
00086 "2. Relative strength\n"
00087 "3. String either containing “Ar” or “Ne”\n"
00088 "The recipe extracts, based on the header keywords, either the applying argon\n"
00089 "and/or neon emission lines. Below are the plots of the emission lines for both\n"
00090 "argon and neon. The marked lines are the ones used for wavelength calibration.\n"
00091 "\n"
00092 "BASIC PARAMETERS:\n"
00093 "-----------------\n"
00094 "--order\n"
00095 "The polynomial order to use for the fit of the wavelength solution.\n"
00096 "0: (default) The appropriate order is choosen automatically depending on the\n"
00097 "waveband. Otherwise an order of 6 is recommended, except for IZ-band, there\n"
00098 "order 4 should be used.\n"
00099 "\n"
00100 "ADVANCED PARAMETERS\n"
00101 "-------------------\n"
00102 "--b_samples\n"
00103 "The number of samples in spectral direction for the reconstructed cube.\n"
00104 "Ideally this number should be greater than 2048, the detector size.\n"
00105 "\n"
00106 "--b_start\n"
00107 "--b_end\n"
00108 "Used to define manually the start and end wavelength for the reconstructed\n"
00109 "cube. By default the internally defined values are used.\n"
00110 "\n"
00111 
00112 "-------------------------------------------------------------------------------\n"
00113 "  Input files:\n"
00114 "\n"
00115 "   DO                    KMOS                                                  \n"
00116 "   category              Type   Explanation                    Required #Frames\n"
00117 "   --------              -----  -----------                    -------- -------\n"
00118 "   ARC_ON                RAW    Arclamp-on exposure                Y          1\n"
00119 "   ARC_OFF               RAW    Arclamp-off exposure               Y          1\n"
00120 "   BADPIXEL_FLAT         B2D    Bad pixel mask                     Y          1\n"
00121 "   XCAL                  F2D    x calibration frame                Y          1\n"
00122 "   YCAL                  F2D    y calibration frame                Y          1\n"
00123 "   ARC_LIST              F2L    List of arclines                   Y          1\n"
00124 "   FLAT_EDGE             F2L    Fitted edge parameters             Y          1\n"
00125 "   REF_LINES             F2L    Reference line table               Y          1\n"
00126 "   WAVE_BAND             F2L    Table with start-/end-wavelengths  Y          1\n"
00127 "\n"
00128 "  Output files:\n"
00129 "\n"
00130 "   DO                    KMOS\n"
00131 "   category              Type   Explanation\n"
00132 "   --------              -----  -----------\n"
00133 "   LCAL                  F2D    Wavelength calibration frame\n"
00134 "                                (3 Extensions)\n"
00135 "   DET_IMG_WAVE          F2D    reconstructed arclamp-on exposure\n"
00136 "                                (4 extensions: 3 detector images + \n"
00137 "                                the arclines list table)\n"
00138 "-------------------------------------------------------------------------------\n"
00139 "\n";
00140 
00141 /*-----------------------------------------------------------------------------
00142  *                              Functions code
00143  *----------------------------------------------------------------------------*/
00144 
00161 int cpl_plugin_get_info(cpl_pluginlist *list)
00162 {
00163     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00164     cpl_plugin *plugin = &recipe->interface;
00165 
00166     cpl_plugin_init(plugin,
00167                         CPL_PLUGIN_API,
00168                         KMOS_BINARY_VERSION,
00169                         CPL_PLUGIN_TYPE_RECIPE,
00170                         "kmo_wave_cal",
00171                         "Create a calibration frame encoding the spectral "
00172                         "position (i.e. wavelength) of each pixel on the "
00173                         "detector.",
00174                         kmo_wave_cal_description,
00175                         "Alex Agudo Berbel",
00176                         "agudo@mpe.mpg.de",
00177                         kmos_get_license(),
00178                         kmo_wave_cal_create,
00179                         kmo_wave_cal_exec,
00180                         kmo_wave_cal_destroy);
00181 
00182     cpl_pluginlist_append(list, plugin);
00183 
00184     return 0;
00185 }
00186 
00194 static int kmo_wave_cal_create(cpl_plugin *plugin)
00195 {
00196     cpl_recipe *recipe;
00197     cpl_parameter *p;
00198 
00199     // Check that the plugin is part of a valid recipe
00200     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00201         recipe = (cpl_recipe *)plugin;
00202     else
00203         return -1;
00204 
00205     // Create the parameters list in the cpl_recipe object
00206     recipe->parameters = cpl_parameterlist_new();
00207 
00208     // Fill the parameters list
00209     p = cpl_parameter_new_value("kmos.kmo_wave_cal.order",
00210                                 CPL_TYPE_INT,
00211                                 "The polynomial order to use for the fit of "
00212                                 "the wavelength solution. 0: (default) The "
00213                                 "appropriate order is choosen automatically "
00214                                 "depending on the waveband. Otherwise an order "
00215                                 "of 6 is recommended, except for IZ-band, there "
00216                                 "order 4 should be used",
00217                                 "kmos.kmo_wave_cal",
00218                                 0);
00219     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "order");
00220     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00221     cpl_parameterlist_append(recipe->parameters, p);
00222 
00223     p = cpl_parameter_new_value("kmos.kmo_wave_cal.dev_flip",
00224                                 CPL_TYPE_BOOL,
00225                                 "Set this parameter to TRUE if the wavelengths"
00226                                 " are ascending on the detector from top to "
00227                                 "bottom.",
00228                                 "kmos.kmo_wave_cal",
00229                                 FALSE);
00230     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_flip");
00231     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00232     cpl_parameterlist_append(recipe->parameters, p);
00233 
00234     p = cpl_parameter_new_value("kmos.kmo_wave_cal.dev_disp",
00235                                 CPL_TYPE_DOUBLE,
00236                                 "The expected dispersion of the wavelength "
00237                                 "in microns/pixel. If the default isn't "
00238                                 "changed it will automatically be selected "
00239                                 "upon header keywords.",
00240                                 "kmos.kmo_wave_cal",
00241                                 -1.0);
00242     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_disp");
00243     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00244     cpl_parameterlist_append(recipe->parameters, p);
00245 
00246     // add parameters for band-definition
00247     kmo_band_pars_create(recipe->parameters,
00248                          "kmos.kmo_wave_cal");
00249 
00250     return 0;
00251 }
00252 
00258 static int kmo_wave_cal_exec(cpl_plugin *plugin)
00259 {
00260     cpl_recipe  *recipe;
00261 
00262     // Get the recipe out of the plugin
00263     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00264         recipe = (cpl_recipe *)plugin;
00265     else return -1;
00266 
00267     return kmo_wave_cal(recipe->parameters, recipe->frames);
00268 }
00269 
00275 static int kmo_wave_cal_destroy(cpl_plugin *plugin)
00276 {
00277     cpl_recipe *recipe;
00278 
00279     // Get the recipe out of the plugin
00280     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00281         recipe = (cpl_recipe *)plugin;
00282     else return -1 ;
00283 
00284     cpl_parameterlist_delete(recipe->parameters);
00285     return 0 ;
00286 }
00287 
00302 static int kmo_wave_cal(cpl_parameterlist *parlist, cpl_frameset *frameset)
00303 {
00304     cpl_image        *det_lamp_on                   = NULL,
00305                      *det_lamp_on_copy              = NULL,
00306                      *det_lamp_off                  = NULL,
00307                      *bad_pix_mask                  = NULL,
00308                      *xcal                          = NULL,
00309                      *ycal                          = NULL,
00310                      *lcal                          = NULL;
00311 
00312     cpl_image        **stored_lcal                  = NULL,
00313                      **stored_det_img               = NULL;
00314 
00315     cpl_frame        *frame                         = NULL;
00316     cpl_frameset     ** angle_frameset     = NULL;
00317 
00318     int              ret_val                        = 0,
00319                      nr_devices                     = 0,
00320                      nr_angles                      = 0,
00321                      nx                             = 0,
00322                      ny                             = 0,
00323                      nz                             = 0,
00324                      *stored_qc_arc_sat             = NULL,
00325                      flip_trace                     = FALSE,
00326                      fit_order_par                  = 0,
00327                      fit_order                      = 0,
00328                      ndit                           = 0,
00329                      line_estimate_method           = 2,
00330                      nr_sat                         = 0;
00331 
00332     double           exptime                        = 0.0,
00333                      gain                           = 0.0,
00334                      *stored_qc_ar_eff              = NULL,
00335                      *stored_qc_ne_eff              = NULL,
00336                      disp                           = 0.0,
00337                      angle_found                    = 0.0;
00338 
00339     cpl_table        *arclines                      = NULL,
00340                      *reflines                      = NULL,
00341                      ***edge_table                  = NULL;
00342 
00343     cpl_propertylist *main_header                   = NULL,
00344                      **stored_sub_headers_lcal      = NULL,
00345                      **stored_sub_headers_det_img   = NULL,
00346                      *qc_header                     = NULL,
00347                      *tmp_header                    = NULL,
00348                      *header                        = NULL;
00349 
00350     cpl_array        **unused_ifus_before           = NULL,
00351                      **unused_ifus_after            = NULL;
00352 
00353     cpl_bivector     *lines                         = NULL;
00354 
00355     main_fits_desc   desc1,
00356                      desc2,
00357                      desc3;
00358 
00359     char             *extname                       = NULL,
00360                      filename_lcal[256],
00361                      filename_det_img[256],
00362                      *suffix                        = NULL,
00363                      tmpstr[256],
00364                      **filter_ids                   = NULL,
00365                      *readmode                      = NULL,
00366                      *str_line_estimate_method      = NULL,
00367                      *last_env                      = NULL;
00368 
00369     const char       *tmp_str                       = NULL;
00370 
00371     cpl_error_code   err                            = CPL_ERROR_NONE;
00372 
00373     enum lampConfiguration lamp_config;
00374 
00375     KMO_TRY
00376     {
00377         kmo_init_fits_desc(&desc1);
00378         kmo_init_fits_desc(&desc2);
00379         kmo_init_fits_desc(&desc3);
00380 
00381         str_line_estimate_method = getenv("KMO_WAVE_LINE_ESTIMATE");
00382         if (str_line_estimate_method != NULL) {
00383             line_estimate_method = atoi(str_line_estimate_method);
00384         }
00385         cpl_msg_debug(cpl_func, "Line estimation method: %d\n",
00386                                 line_estimate_method);
00387 
00388 // #############################################################################
00389 // ###           check inputs
00390 // #############################################################################
00391         KMO_TRY_ASSURE((parlist != NULL) &&
00392                        (frameset != NULL),
00393                        CPL_ERROR_NULL_INPUT,
00394                        "Not all input data is provided!");
00395 
00396         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, ARC_ON) >= 1,
00397                        CPL_ERROR_NULL_INPUT,
00398                        "At least one ARC_ON frame is required!");
00399 
00400         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, ARC_OFF) == 1,
00401                        CPL_ERROR_NULL_INPUT,
00402                        "Exactly one ARC_OFF frame is required!");
00403 
00404         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, BADPIXEL_FLAT) == 1,
00405                        CPL_ERROR_FILE_NOT_FOUND,
00406                        "Exactly one BADPIXEL_FLAT frame is required!");
00407 
00408         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00409                        CPL_ERROR_FILE_NOT_FOUND,
00410                        "Exactly one XCAL frame is required!");
00411 
00412         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00413                        CPL_ERROR_FILE_NOT_FOUND,
00414                        "Exactly one YCAL frame is required!");
00415 
00416         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, ARC_LIST) == 1,
00417                        CPL_ERROR_FILE_NOT_FOUND,
00418                        "Exactly one ARC_LIST frame is required!");
00419 
00420         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, FLAT_EDGE) == 1,
00421                        CPL_ERROR_FILE_NOT_FOUND,
00422                        "Exactly one FLAT_EDGE frame is required!");
00423 
00424         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00425                        CPL_ERROR_FILE_NOT_FOUND,
00426                        "Exactly one WAVE_BAND frame is required!");
00427 
00428         if (line_estimate_method == 2) {
00429             KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, REF_LINES) == 1,
00430                            CPL_ERROR_FILE_NOT_FOUND,
00431                            "Exactly one REF_LINES frame is required!");
00432         }
00433         
00434         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_wave_cal") == 1,
00435                        CPL_ERROR_ILLEGAL_INPUT,
00436                        "Cannot identify RAW and CALIB frames!");
00437 
00438         //
00439         // ------------ get parameters ------------
00440         //
00441         cpl_msg_info("", "--- Parameter setup for kmo_wave_cal ------");
00442 
00443         fit_order_par = kmo_dfs_get_parameter_int(parlist,
00444                                               "kmos.kmo_wave_cal.order");
00445         KMO_TRY_CHECK_ERROR_STATE();
00446         KMO_TRY_EXIT_IF_ERROR(
00447             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_wave_cal.order"));
00448         KMO_TRY_ASSURE((fit_order_par >= 0) &&
00449                        (fit_order_par <= 8),
00450                        CPL_ERROR_ILLEGAL_INPUT,
00451                        "order must be between 1 and 8!");
00452 
00453         flip_trace = kmo_dfs_get_parameter_bool(parlist,
00454                                            "kmos.kmo_wave_cal.dev_flip");
00455         KMO_TRY_CHECK_ERROR_STATE();
00456         KMO_TRY_EXIT_IF_ERROR(
00457             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_wave_cal.dev_flip"));
00458         KMO_TRY_ASSURE((flip_trace == TRUE) ||
00459                        (flip_trace == FALSE),
00460                        CPL_ERROR_ILLEGAL_INPUT,
00461                        "flip must be TRUE or FALSE!");
00462 
00463         disp = kmo_dfs_get_parameter_double(parlist,
00464                                            "kmos.kmo_wave_cal.dev_disp");
00465         KMO_TRY_CHECK_ERROR_STATE();
00466         KMO_TRY_EXIT_IF_ERROR(
00467             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_wave_cal.dev_disp"));
00468 
00469         KMO_TRY_ASSURE((disp > 0.0) || (disp == -1.0),
00470                        CPL_ERROR_ILLEGAL_INPUT,
00471                        "dispersion must be greater than 0.0!");
00472 
00473         kmo_band_pars_load(parlist, "kmos.kmo_wave_cal");
00474 
00475         cpl_msg_info("", "-------------------------------------------");
00476 
00477         KMO_TRY_EXIT_IF_NULL(
00478             frame = kmo_dfs_get_frame(frameset, BADPIXEL_FLAT));
00479 
00480         desc2 = kmo_identify_fits_header(
00481                     cpl_frame_get_filename(frame));
00482         KMO_TRY_CHECK_ERROR_STATE();
00483 
00484         KMO_TRY_ASSURE((desc2.nr_ext % 3 == 0) &&
00485                        (desc2.ex_badpix == TRUE) &&
00486                        (desc2.fits_type == b2d_fits) &&
00487                        (desc2.frame_type == detector_frame),
00488                        CPL_ERROR_ILLEGAL_INPUT,
00489                        "BADPIXEL_FLAT isn't in the correct format!!!");
00490 
00491         nx = desc2.naxis1;
00492         ny = desc2.naxis2;
00493         nz = desc2.naxis3;
00494 
00495         //
00496         // ------------ check EXPTIME, NDIT, READMODE and lamps ------------
00497         //
00498 
00499         // check ARC_OFF
00500         KMO_TRY_EXIT_IF_NULL(
00501             frame = kmo_dfs_get_frame(frameset, ARC_OFF));
00502 
00503         main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0);
00504 
00505         ndit = cpl_propertylist_get_int(main_header, NDIT);
00506         KMO_TRY_CHECK_ERROR_STATE("NDIT keyword in main header "
00507                                   "missing!");
00508 
00509         exptime = cpl_propertylist_get_double(main_header, EXPTIME);
00510         KMO_TRY_CHECK_ERROR_STATE("EXPTIME keyword in main header "
00511                                   "missing!");
00512 
00513         readmode = cpl_strdup(cpl_propertylist_get_string(main_header, READMODE));
00514         KMO_TRY_CHECK_ERROR_STATE("ESO DET READ CURNAME keyword in main "
00515                                   "header missing!");
00516 
00517         desc1 = kmo_identify_fits_header(
00518                     cpl_frame_get_filename(frame));
00519         KMO_TRY_CHECK_ERROR_STATE_MSG("ARC_OFF frame doesn't seem to "
00520                                       "be in KMOS-format!");
00521 
00522         KMO_TRY_ASSURE(desc1.fits_type == raw_fits,
00523                        CPL_ERROR_ILLEGAL_INPUT,
00524                        "ARC_OFF frame hasn't correct data type "
00525                        "(%s must be a raw, unprocessed file)!",
00526                        cpl_frame_get_filename(frame));
00527 
00528         KMO_TRY_ASSURE((desc1.naxis1 == nx) &&
00529                        (desc1.naxis2 == ny) &&
00530                        (desc1.naxis3 == nz),
00531                        CPL_ERROR_ILLEGAL_INPUT,
00532                        "ARC_OFF frame hasn't correct dimensions! (x,y): (%d,%d) "
00533                        "vs (%d,%d)", desc1.naxis1, desc1.naxis2, nx, ny);
00534 
00535         // assure that flat lamps are off
00536         KMO_TRY_ASSURE((kmo_check_lamp(main_header, INS_LAMP3_ST) == FALSE) &&
00537                        (kmo_check_lamp(main_header, INS_LAMP4_ST) == FALSE),
00538                        CPL_ERROR_ILLEGAL_INPUT,
00539                        "Flat lamps must be switched off (%s)!",
00540                        cpl_frame_get_filename(frame));
00541 
00542         // check if arc lamps are off (or at least blocked by filter wheel)
00543         if ((kmo_check_lamp(main_header, INS_LAMP1_ST) == TRUE) ||
00544             (kmo_check_lamp(main_header, INS_LAMP2_ST) == TRUE))
00545         {
00546             if (!(strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT1 ID"), "Block") == 0) ||
00547                 !(strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT3 ID"), "Block") == 0) ||
00548                 !(strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT3 ID"), "Block") == 0))
00549             {
00550                 cpl_msg_warning("","At least one arc lamp is on! Check if the lamps are blocked!");
00551             }
00552         }
00553 
00554 
00555         kmo_free_fits_desc(&desc1);
00556         cpl_propertylist_delete(main_header); main_header = NULL;
00557 
00558         // check REF_LINES
00559         if (line_estimate_method == 2) {
00560             KMO_TRY_EXIT_IF_NULL(
00561                 frame = kmo_dfs_get_frame(frameset, REF_LINES));
00562             desc1 = kmo_identify_fits_header(
00563                         cpl_frame_get_filename(frame));
00564             KMO_TRY_CHECK_ERROR_STATE_MSG("REF_LINES frame doesn't seem to "
00565                                           "be in KMOS-format!");
00566 
00567             KMO_TRY_ASSURE(desc1.fits_type == f2l_fits,
00568                            CPL_ERROR_ILLEGAL_INPUT,
00569                            "REF_LINES frame hasn't correct frame type "
00570                            "(%s must be a F2L frame)!",
00571                            cpl_frame_get_filename(frame));
00572             kmo_free_fits_desc(&desc1);
00573         }
00574 
00575         // check ARC_ON
00576         KMO_TRY_EXIT_IF_NULL(
00577             frame = kmo_dfs_get_frame(frameset, ARC_ON));
00578 
00579         while (frame != NULL) {
00580 
00581             main_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0);
00582 
00583             KMO_TRY_ASSURE(cpl_propertylist_get_int(main_header, NDIT) == ndit,
00584                     CPL_ERROR_ILLEGAL_INPUT,
00585                     "NDIT isn't the same for all frames: (is %d and %d).",
00586                     cpl_propertylist_get_int(main_header, NDIT), ndit);
00587 
00588             KMO_TRY_ASSURE(cpl_propertylist_get_double(main_header, EXPTIME) == exptime,
00589                     CPL_ERROR_ILLEGAL_INPUT,
00590                     "EXPTIME isn't the same for all frames: (is %g and %g).",
00591                     cpl_propertylist_get_double(main_header, EXPTIME), exptime);
00592 
00593             KMO_TRY_ASSURE(strcmp(cpl_propertylist_get_string(main_header, READMODE), readmode) == 0,
00594                     CPL_ERROR_ILLEGAL_INPUT,
00595                     "ESO DET READ CURNAME isn't the same for all frames: (is %s and %s).",
00596                     cpl_propertylist_get_string(main_header, READMODE), readmode);
00597 
00598             desc1 = kmo_identify_fits_header(
00599                     cpl_frame_get_filename(frame));
00600             KMO_TRY_CHECK_ERROR_STATE_MSG("ARC_ON frame doesn't seem to "
00601                     "be in KMOS-format!");
00602 
00603             KMO_TRY_ASSURE(desc1.fits_type == raw_fits,
00604                     CPL_ERROR_ILLEGAL_INPUT,
00605                     "ARC_ON frame hasn't correct data type "
00606                     "(%s must be a raw, unprocessed file)!",
00607                     cpl_frame_get_filename(frame));
00608 
00609             KMO_TRY_ASSURE((desc1.naxis1 == nx) &&
00610                     (desc1.naxis2 == ny) &&
00611                     (desc1.naxis3 == nz),
00612                     CPL_ERROR_ILLEGAL_INPUT,
00613                     "ARC_ON frame hasn't correct dimensions! (x,y): (%d,%d) "
00614                     "vs (%d,%d)", desc1.naxis1, desc1.naxis2, nx, ny);
00615 
00616 
00617             // assure that flat lamp is off (LAMP3 and 4)
00618             // and that either arc lamp is on (LAMP1 and 2)
00619             KMO_TRY_ASSURE(((kmo_check_lamp(main_header, INS_LAMP1_ST) == TRUE) ||
00620                     (kmo_check_lamp(main_header, INS_LAMP2_ST) == TRUE)) &&
00621                     (kmo_check_lamp(main_header, INS_LAMP3_ST) == FALSE) &&
00622                     (kmo_check_lamp(main_header, INS_LAMP4_ST) == FALSE),
00623                     CPL_ERROR_ILLEGAL_INPUT,
00624                     "Lamp1 or Lamp2 must be switched on, 3 and 4 must be "
00625                     "off for the ARC_ON frame");
00626 
00627             frame = kmo_dfs_get_frame(frameset, NULL);
00628             KMO_TRY_CHECK_ERROR_STATE();
00629         }
00630 
00631         // check FLAT_EDGE
00632         KMO_TRY_EXIT_IF_NULL(
00633             frame = kmo_dfs_get_frame(frameset, FLAT_EDGE));
00634 
00635         desc3 = kmo_identify_fits_header(
00636                     cpl_frame_get_filename(frame));
00637         KMO_TRY_CHECK_ERROR_STATE();
00638 
00639         KMO_TRY_ASSURE((desc3.nr_ext % 24== 0) &&
00640                        (desc3.fits_type == f2l_fits),
00641                        CPL_ERROR_ILLEGAL_INPUT,
00642                        "FLAT_EDGE isn't in the correct format!!!");
00643 
00644         kmo_free_fits_desc(&desc3);
00645         kmo_init_fits_desc(&desc3);
00646 
00647         //
00648         // ------------ check filter_id, grating_id and rotator offset ---------
00649         // assure that filters, grating and rotation offsets match for
00650         // ARC_ON, BADPIXEL_FLAT, XCAL and YCAL
00651         // check if filter_id, grating_id and rotator offset match for all
00652         // detectors
00653         //
00654         KMO_TRY_EXIT_IF_ERROR(
00655             kmo_check_frame_setup(frameset, ARC_ON, BADPIXEL_FLAT,
00656                                        TRUE, FALSE, FALSE));
00657         KMO_TRY_EXIT_IF_ERROR(
00658             kmo_check_frame_setup(frameset, ARC_ON, XCAL,
00659                                        TRUE, FALSE, FALSE));
00660         KMO_TRY_EXIT_IF_ERROR(
00661             kmo_check_frame_setup(frameset, ARC_ON, YCAL,
00662                                        TRUE, FALSE, FALSE));
00663 
00664 //        KMO_TRY_EXIT_IF_ERROR(
00665 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00666 
00667         strcpy(filename_lcal, LCAL);
00668         strcpy(filename_det_img, DET_IMG_WAVE);
00669 
00670         KMO_TRY_EXIT_IF_NULL(
00671             frame = kmo_dfs_get_frame(frameset, XCAL));
00672         KMO_TRY_EXIT_IF_NULL(
00673             suffix = kmo_dfs_get_suffix(frame, TRUE, FALSE));
00674 
00675         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00676         cpl_msg_info("", "(grating 1, 2 & 3)");
00677 
00678         // setup lamp config
00679         if ((kmo_check_lamp(main_header, INS_LAMP1_ST) == TRUE) &&
00680             (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE))
00681         {
00682             lamp_config = ARGON;
00683             strcpy(tmpstr, "Argon");
00684         } else if ((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) &&
00685                    (kmo_check_lamp(main_header, INS_LAMP2_ST) == TRUE))
00686         {
00687            lamp_config = NEON;
00688            strcpy(tmpstr, "Neon");
00689         } else if ((kmo_check_lamp(main_header, INS_LAMP1_ST) == TRUE) &&
00690                    (kmo_check_lamp(main_header, INS_LAMP2_ST) == TRUE))
00691         {
00692            lamp_config = ARGON_NEON;
00693            strcpy(tmpstr, "Argon + Neon");
00694         }
00695 
00696         cpl_msg_info("", "Detected arc lamp configuration: %s", tmpstr);
00697 
00698         nr_devices = desc1.nr_ext;
00699 
00700         //assert that filter and grating match for each detector
00701         // filter/grating can be different for each detector
00702         KMO_TRY_EXIT_IF_NULL(
00703             filter_ids =  kmo_get_filter_setup(main_header,
00704                                      nr_devices, TRUE));
00705 
00706         //
00707         // ---- scan for rotator angles
00708         //
00709 #define ANGLE_DIM 360
00710        int rotang_found[ANGLE_DIM];
00711        int rotang_cnt[ANGLE_DIM];
00712         for (int i=0; i<ANGLE_DIM; i++) {
00713             rotang_found[i] = 0;
00714             rotang_cnt[i] = 0;
00715         }
00716         KMO_TRY_EXIT_IF_NULL(
00717             frame = kmo_dfs_get_frame(frameset, ARC_ON));
00718         while (frame != NULL) {
00719             header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0);
00720             if (cpl_propertylist_has(header, ROTANGLE)) {
00721                 int rot_angle = (int) rint(cpl_propertylist_get_double(header, ROTANGLE));
00722                 if (rot_angle < 0) {
00723                     rot_angle += 360;
00724                 }
00725                 if (rot_angle < 360 && rot_angle >= 0) {
00726                     rotang_cnt[rot_angle]++;
00727 //                    char * tag = cpl_sprintf("FLAT_ON_%3.3d",rot_angle);
00728 //                    KMO_TRY_EXIT_IF_ERROR(
00729 //                            cpl_frame_set_tag(frame, tag));
00730 //                    cpl_free(tag);
00731                 }
00732             } else {
00733                 cpl_msg_warning("","File %s has no keyword \"ROTANGLE\"",
00734                         cpl_frame_get_filename(frame));
00735             }
00736 
00737             cpl_propertylist_delete(header); header = NULL;
00738             frame = kmo_dfs_get_frame(frameset, NULL);
00739             KMO_TRY_CHECK_ERROR_STATE();
00740         }
00741         for (int ax=0; ax<ANGLE_DIM; ax++) {
00742             if (rotang_cnt[ax] != 0) {
00743                 if (rotang_cnt[ax] == 1 ) {
00744                     cpl_msg_info("","Found %d frame with rotator angle %d",rotang_cnt[ax],ax);
00745                 } else {
00746                     cpl_msg_warning("","Found %d frames with rotator angle %d but only one will be used",
00747                                     rotang_cnt[ax],ax);
00748                 }
00749                 rotang_found[nr_angles] = ax;
00750                 nr_angles++;
00751             }
00752         }
00753 
00754         KMO_TRY_EXIT_IF_NULL (
00755             angle_frameset = (cpl_frameset **) cpl_malloc(nr_angles * sizeof(cpl_frameset*)));
00756         for (int i =0; i<nr_angles; i++) {
00757             angle_frameset[i] = cpl_frameset_new();
00758         }
00759 
00760         KMO_TRY_EXIT_IF_NULL(
00761             frame = kmo_dfs_get_frame(frameset, ARC_ON));
00762         while (frame != NULL) {
00763             header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0);
00764             if (cpl_propertylist_has(header, ROTANGLE)) {
00765                 int rot_angle = (int) rint(cpl_propertylist_get_double(header, ROTANGLE));
00766                 if (rot_angle < 0) {
00767                     rot_angle += 360;
00768                 }
00769                 int ix = -1;
00770                 for (ix = 0; ix<nr_angles; ix++) {
00771                     if (rotang_found[ix] == rot_angle) {
00772                         break;
00773                     }
00774                 }
00775                 if (ix<nr_angles) {
00776                     KMO_TRY_EXIT_IF_ERROR(
00777                         cpl_frameset_insert(angle_frameset[ix], cpl_frame_duplicate(frame)));
00778                 }
00779             }
00780 
00781             cpl_propertylist_delete(header); header = NULL;
00782             frame = kmo_dfs_get_frame(frameset, NULL);
00783             KMO_TRY_CHECK_ERROR_STATE();
00784         }
00785 
00786 // #############################################################################
00787 // ###           allocate temporary memory
00788 // #############################################################################
00789         // allocate here a edge table structure for all detectors
00790         KMO_TRY_EXIT_IF_NULL(
00791             edge_table = (cpl_table***)cpl_calloc(nr_devices,
00792                                                   sizeof(cpl_table**)));
00793         for (int i = 0; i < nr_devices; i++) {
00794             KMO_TRY_EXIT_IF_NULL(
00795                 edge_table[i] = (cpl_table**)cpl_calloc(KMOS_IFUS_PER_DETECTOR,
00796                                                         sizeof(cpl_table*)));
00797         }
00798 
00799         // the frames have to be stored temporarily because the QC parameters
00800         // for the main header are calculated from each detector. So they can be
00801         // stored only when all detectors are processed
00802         KMO_TRY_EXIT_IF_NULL(
00803             stored_lcal = (cpl_image**)cpl_calloc(nr_devices * nr_angles,
00804                                                     sizeof(cpl_image*)));
00805         KMO_TRY_EXIT_IF_NULL(
00806             stored_det_img = (cpl_image**)cpl_calloc(nr_devices * nr_angles,
00807                                                     sizeof(cpl_image*)));
00808         KMO_TRY_EXIT_IF_NULL(
00809             stored_sub_headers_lcal = (cpl_propertylist**)cpl_calloc(nr_devices * nr_angles,
00810                                                     sizeof(cpl_propertylist*)));
00811         KMO_TRY_EXIT_IF_NULL(
00812             stored_sub_headers_det_img = (cpl_propertylist**)cpl_calloc(nr_devices * nr_angles,
00813                                                     sizeof(cpl_propertylist*)));
00814         KMO_TRY_EXIT_IF_NULL(
00815             stored_qc_arc_sat =
00816                             (int*)cpl_calloc(nr_devices, nr_angles * sizeof(int)));
00817         KMO_TRY_EXIT_IF_NULL(
00818             stored_qc_ar_eff =
00819                             (double*)cpl_calloc(nr_devices, nr_angles * sizeof(double)));
00820         KMO_TRY_EXIT_IF_NULL(
00821             stored_qc_ne_eff =
00822                             (double*)cpl_calloc(nr_devices, nr_angles * sizeof(double)));
00823 
00824 // #############################################################################
00825 // ###           process data
00826 // #############################################################################
00827         // load arclines and reference lines
00828         KMO_TRY_EXIT_IF_NULL(
00829             frame = kmo_dfs_get_frame(frameset, ARC_LIST));
00830 
00831         // check if ARC_LIST is the filter_id-one
00832         KMO_TRY_EXIT_IF_NULL(
00833             tmp_header = kmclipm_propertylist_load(cpl_frame_get_filename(frame), 0));
00834         KMO_TRY_EXIT_IF_NULL(
00835             tmp_str = cpl_propertylist_get_string(tmp_header, FILT_ID));
00836         KMO_TRY_ASSURE(strcmp(filter_ids[0], tmp_str) == 0,
00837                        CPL_ERROR_ILLEGAL_INPUT,
00838                        "ARC_LIST model must have primary "
00839                        "keyword '%s' equal '%s'!!!", FILT_ID, filter_ids[0]);
00840         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00841 
00842         desc3 = kmo_identify_fits_header(
00843                     cpl_frame_get_filename(frame));
00844         KMO_TRY_CHECK_ERROR_STATE();
00845 
00846         KMO_TRY_ASSURE((desc3.nr_ext == 1) &&
00847                        (desc3.fits_type == f2l_fits),
00848                        CPL_ERROR_ILLEGAL_INPUT,
00849                        "ARC_LIST isn't in the correct format!!!");
00850 
00851         KMO_TRY_EXIT_IF_NULL(
00852             arclines = kmo_dfs_load_table(frameset, ARC_LIST, 1, 0));
00853 
00854         KMO_TRY_EXIT_IF_NULL(
00855             lines = kmo_get_lines(arclines, lamp_config));
00856 
00857         cpl_msg_info("", "Nr. of lines in arclist for this configuration: %lld",
00858                      cpl_bivector_get_size(lines));
00859 
00860         if (line_estimate_method == 2) {
00861             KMO_TRY_EXIT_IF_NULL(
00862                 reflines = kmo_dfs_load_table(frameset, REF_LINES, 1, 0));
00863         }
00864 
00865         // check which IFUs are active for all FLAT frames
00866         KMO_TRY_EXIT_IF_NULL(
00867             unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0));
00868 
00869         KMO_TRY_EXIT_IF_NULL(
00870             unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before));
00871 
00872         kmo_print_unused_ifus(unused_ifus_before, FALSE);
00873 
00874         // make sure no reconstruction lookup table (LUT) is used
00875         if (getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE") != NULL) {
00876             last_env = getenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE");
00877         }
00878         setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE","NONE",1);
00879 
00880         //
00881         // ------------ loop all rotator angles and detectors ------------
00882         //
00883         for (int a = 0; a<nr_angles; a++) {
00884             cpl_msg_info("","Processing rotator angle %d -> %d degree", a,rotang_found[a]);
00885 
00886 
00887         for (int i = 1; i <= nr_devices; i++) {
00888             // use loop below for line identification
00889 //            for (int i = 1; i <= 1; i++) {
00890 
00891             cpl_msg_info("","Processing detector No. %d", i);
00892 
00893             int sx = a * nr_devices + (i - 1);
00894 
00895             // load edge parameters
00896             KMO_TRY_EXIT_IF_NULL(
00897                 frame = kmo_dfs_get_frame(frameset, FLAT_EDGE));
00898 
00899             for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00900                 edge_table[i-1][j] = kmclipm_cal_table_load(cpl_frame_get_filename(frame),
00901                                                   (i-1) * KMOS_IFUS_PER_DETECTOR + j + 1,
00902                                                   rotang_found[a], 0, &angle_found);
00903                 if (cpl_error_get_code() == CPL_ERROR_ILLEGAL_INPUT) {
00904                     // IFU is inactive: proceed
00905                     cpl_error_reset();
00906                 }
00907             }
00908 
00909             if (fit_order_par == 0) {
00910                 // set default fit orders for the different bands
00911                 if ((strcmp(filter_ids[i-1], "H") == 0) ||
00912                     (strcmp(filter_ids[i-1], "K") == 0) ||
00913                     (strcmp(filter_ids[i-1], "YJ") == 0))
00914                 {
00915                     fit_order = 6;
00916                 } else if (strcmp(filter_ids[i-1], "IZ") == 0) {
00917                     fit_order = 4;
00918                 } else if (strcmp(filter_ids[i-1], "HK") == 0) {
00919                     fit_order = 5;
00920                 }
00921                 cpl_msg_info("", "Order of wavelength spectrum fit for %s-band: %d",
00922                              filter_ids[i-1],
00923                              fit_order);
00924             } else {
00925                 fit_order = fit_order_par;
00926             }
00927 
00928 //            int cnt_invalid = 0;
00929 //            for (int k = 0; k < KMOS_IFUS_PER_DETECTOR; k++) {
00930 //                if ((cpl_array_get_int(unused_ifus_after[i-1], k, NULL) == 1) ||
00931 //                    (cpl_array_get_int(unused_ifus_after[i-1], k, NULL) == 2))
00932 //                {
00933 //                    cnt_invalid++;
00934 //                }
00935 //            }
00936 //            if (cnt_invalid == KMOS_IFUS_PER_DETECTOR) {
00937 //                // all IFUs invalid on this detector,
00938 //                // skip this detector and continue with next one
00939 //                continue;
00940 //            }
00941 
00942             // lamp_on
00943             KMO_TRY_EXIT_IF_NULL(
00944                 frame = kmo_dfs_get_frame(angle_frameset[a], ARC_ON));
00945 
00946             // if sat_mode is set to TRUE here, then the calculation of the
00947             // saturated pixels has to be updated like in kmo_flat-recipe
00948             KMO_TRY_EXIT_IF_NULL(
00949                 det_lamp_on = kmo_dfs_load_image_frame(frame, i, FALSE, TRUE, &nr_sat));
00950 
00951             // count saturated pixels for each detector
00952             if (strcmp(cpl_propertylist_get_string(main_header, READMODE), "Nondest") == 0) {
00953                 // NDR: non-destructive readout mode
00954                 stored_qc_arc_sat[sx] = nr_sat;
00955             } else {
00956                 // normal readout mode
00957                 stored_qc_arc_sat[sx] = kmo_image_get_saturated(det_lamp_on,
00958                                                             KMO_FLAT_SATURATED);
00959             }
00960             KMO_TRY_CHECK_ERROR_STATE();
00961 
00962 
00963             KMO_TRY_EXIT_IF_NULL(
00964                 det_lamp_on_copy = cpl_image_duplicate(det_lamp_on));
00965 
00966             // lamp_off
00967             KMO_TRY_EXIT_IF_NULL(
00968                 frame = kmo_dfs_get_frame(frameset, ARC_OFF));
00969 
00970             KMO_TRY_EXIT_IF_NULL(
00971                 det_lamp_off = kmo_dfs_load_image_frame(frame, i, FALSE, FALSE, NULL));
00972 
00973             // process imagelist
00974 
00975 
00976             KMO_TRY_CHECK_ERROR_STATE();
00977 
00978             // subtract lamp_off from lamp_on
00979             KMO_TRY_EXIT_IF_ERROR(
00980                 cpl_image_subtract(det_lamp_on, det_lamp_off));
00981 
00982             // load bad pixel masks
00983             KMO_TRY_EXIT_IF_NULL(
00984                 bad_pix_mask = kmo_dfs_load_cal_image(frameset, BADPIXEL_FLAT, i, 2,
00985                                           (double) rotang_found[a], FALSE, NULL, &angle_found));
00986 
00987             // load flat calibration frames
00988             KMO_TRY_EXIT_IF_NULL(
00989                 xcal = kmo_dfs_load_cal_image(frameset, XCAL, i, 0,
00990                                            (double) rotang_found[a], FALSE, NULL, &angle_found));
00991 
00992             KMO_TRY_EXIT_IF_NULL(
00993                 ycal = kmo_dfs_load_cal_image(frameset, YCAL, i, 0,
00994                                           (double) rotang_found[a], FALSE, NULL,  &angle_found));
00995 
00996             // calculate spectral curvature here
00997             err = kmo_calc_wave_calib(det_lamp_on,
00998                                       bad_pix_mask,
00999                                       xcal,
01000                                       ycal,
01001                                       filter_ids[i-1],
01002                                       lamp_config,
01003                                       i,
01004                                       unused_ifus_after[i-1],
01005                                       edge_table[i-1],
01006                                       lines,
01007                                       reflines,
01008                                       disp,
01009                                       &lcal,
01010                                       &(stored_qc_ar_eff[sx]),
01011                                       &(stored_qc_ne_eff[sx]),
01012                                       flip_trace,
01013                                       fit_order,
01014                                       line_estimate_method);
01015 
01016             if (err == CPL_ERROR_NONE) {
01017                 // calculate QC parameters
01018                 if (stored_qc_ar_eff[sx] != -1.0) {
01019                     stored_qc_ar_eff[sx] /= exptime;
01020                 }
01021                 if (stored_qc_ne_eff[sx] != -1.0) {
01022                     stored_qc_ne_eff[sx] /= exptime;
01023                 }
01024 
01025                 // apply the badpixel mask to the produced frame
01026 
01027                 KMO_TRY_EXIT_IF_ERROR(
01028                     cpl_image_multiply(lcal, bad_pix_mask));
01029 
01030                 KMO_TRY_EXIT_IF_ERROR(
01031                     kmo_image_reject_from_mask(lcal, bad_pix_mask));
01032 
01033                 // store flat frames, badpixel mask and calibration frames
01034                 stored_lcal[sx] = lcal;
01035             } else if (err == CPL_ERROR_UNSPECIFIED) {
01036                 // all IFUs seem to be deativated, continue processing
01037                 // just save empty frame
01038                 cpl_error_reset();
01039                 stored_lcal[sx] = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01040                 kmo_image_fill(stored_lcal[sx], 0.0);
01041             } else {
01042                 cpl_msg_warning(cpl_func,
01043                                 "Couldn't identify any lines! Is the line "
01044                                 "list defined correctly?");
01045                 cpl_msg_warning(cpl_func,
01046                                 "Band defined in header of detector %d: %s",
01047                                 i, filter_ids[i-1]);
01048                 cpl_msg_warning(cpl_func,
01049                                 "Arc line file defined: %s",
01050                                 cpl_frame_get_filename(
01051                                       kmo_dfs_get_frame(frameset, ARC_LIST)));
01052                 cpl_error_reset();
01053             }
01054 
01055 
01056             //
01057             // create reconstructed and resampled arc frame
01058             //
01059             stored_det_img[sx] = kmo_reconstructed_arc_image(frameset,
01060                                                               det_lamp_on_copy,
01061                                                               det_lamp_off,
01062                                                               xcal,
01063                                                               ycal,
01064                                                               stored_lcal[sx],
01065                                                               unused_ifus_after[i-1],
01066                                                               flip_trace,
01067                                                               i,
01068                                                               suffix,
01069                                                               filter_ids[i-1],
01070                                                               lamp_config,
01071                                                               rotang_found[a],
01072                                                               &qc_header);
01073             if (cpl_error_get_code() != CPL_ERROR_NONE) {
01074                 // couldn't reconstruct
01075                 cpl_msg_error("","Couldn't reconstruct IFUs on detector %d", i);
01076                 cpl_error_reset();
01077             }
01078 
01079             // load and update sub_header with QC parameters
01080             KMO_TRY_EXIT_IF_NULL(
01081                 stored_sub_headers_lcal[sx] = kmo_dfs_load_sub_header(frameset,
01082                                                                        ARC_ON, i,
01083                                                                        FALSE));
01084 
01085             // update EXTNAME
01086             KMO_TRY_EXIT_IF_NULL(
01087                 extname = kmo_extname_creator(detector_frame, i, EXT_DATA));
01088             KMO_TRY_EXIT_IF_ERROR(
01089                 kmclipm_update_property_string(stored_sub_headers_lcal[sx],
01090                                         EXTNAME,
01091                                         extname,
01092                                         "FITS extension name"));
01093             cpl_free(extname); extname = NULL;
01094 
01095             // add first QC parameters
01096             KMO_TRY_EXIT_IF_ERROR(
01097                 kmclipm_update_property_int(stored_sub_headers_lcal[sx],
01098                                         QC_ARC_SAT,
01099                                         stored_qc_arc_sat[sx],
01100                                         "[] nr. saturated pixels of arc exp."));
01101 
01102             gain = kmo_dfs_get_property_double(stored_sub_headers_lcal[sx], GAIN);
01103             KMO_TRY_CHECK_ERROR_STATE_MSG(
01104                 "GAIN-keyword in fits-header is missing!");
01105 
01106             if (stored_qc_ar_eff[sx] != -1.0) {
01107                 KMO_TRY_EXIT_IF_ERROR(
01108                     kmclipm_update_property_double(stored_sub_headers_lcal[sx],
01109                                               QC_ARC_AR_EFF,
01110                                               stored_qc_ar_eff[sx]/gain,
01111                                               "[e-/s] Argon lamp efficiency"));
01112             }
01113 
01114             if (stored_qc_ne_eff[sx] != -1.0) {
01115                 KMO_TRY_EXIT_IF_ERROR(
01116                     kmclipm_update_property_double(stored_sub_headers_lcal[sx],
01117                                                QC_ARC_NE_EFF,
01118                                                stored_qc_ne_eff[sx]/gain,
01119                                                "[e-/s] Neon lamp efficiency"));
01120             }
01121 
01122             KMO_TRY_EXIT_IF_ERROR(
01123                     kmclipm_update_property_double(stored_sub_headers_lcal[sx],CAL_ROTANGLE,
01124                             ((double) rotang_found[a]),"[deg] Rotator relative to nasmyth"));
01125 
01126 
01127             // append QC parameters
01128             KMO_TRY_EXIT_IF_ERROR(
01129                 cpl_propertylist_append(stored_sub_headers_lcal[sx],
01130                                         qc_header));
01131             cpl_propertylist_delete(qc_header); qc_header = NULL;
01132 
01133             KMO_TRY_EXIT_IF_NULL(
01134                 stored_sub_headers_det_img[sx] = cpl_propertylist_duplicate(
01135                                                  stored_sub_headers_lcal[sx]));
01136 
01137             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL1);
01138             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRVAL2);
01139             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE1);
01140             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CTYPE2);
01141             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT1);
01142             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CDELT2);
01143 
01144             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRPIX1);
01145             cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRPIX2);
01146             if (cpl_propertylist_has(stored_sub_headers_lcal[sx], CRPIX1)) {
01147                 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRPIX1);
01148             }
01149             if (cpl_propertylist_has(stored_sub_headers_lcal[sx], CRPIX2)) {
01150                 cpl_propertylist_erase(stored_sub_headers_lcal[sx], CRPIX2);
01151             }
01152 
01153             // free memory
01154             cpl_image_delete(det_lamp_on); det_lamp_on = NULL;
01155             cpl_image_delete(det_lamp_on_copy); det_lamp_on_copy = NULL;
01156             cpl_image_delete(det_lamp_off); det_lamp_off = NULL;
01157             cpl_image_delete(bad_pix_mask); bad_pix_mask = NULL;
01158             cpl_image_delete(xcal); xcal = NULL;
01159             cpl_image_delete(ycal); ycal = NULL;
01160         } // for i devices
01161         } // for a angles
01162 
01163         if (line_estimate_method == 2) {
01164             cpl_table_delete(reflines); reflines = NULL;
01165         }
01166 // ###########################################################################
01167 // ###           QC parameters & saving
01168 // ###########################################################################
01169         cpl_msg_info("","Saving data...");
01170 
01171         //
01172         // ------------ load, update & save primary header ------------
01173         //
01174 
01175         // update which IFUs are not used
01176         KMO_TRY_EXIT_IF_ERROR(
01177             kmo_set_unused_ifus(unused_ifus_after, main_header,
01178                                 "kmo_wave_cal"));
01179 
01180         KMO_TRY_EXIT_IF_NULL(
01181             frame = kmo_dfs_get_frame(frameset, ARC_ON));
01182 
01183         KMO_TRY_EXIT_IF_ERROR(
01184             kmo_dfs_save_main_header(frameset, filename_lcal, suffix, frame,
01185                                      main_header, parlist, cpl_func));
01186 
01187         KMO_TRY_EXIT_IF_ERROR(
01188             kmo_dfs_save_main_header(frameset, filename_det_img, suffix, frame,
01189                                      main_header, parlist, cpl_func));
01190 
01191         cpl_propertylist_delete(main_header); main_header = NULL;
01192 
01193         //
01194         // --- save sub-frames ---
01195         //
01196         for (int a = 0; a<nr_angles; a++) {
01197         for (int i = 1; i <= nr_devices; i++) {
01198             int sx = a * nr_devices + (i - 1);
01199             // save lcal-frame
01200             KMO_TRY_EXIT_IF_ERROR(
01201                 kmo_dfs_save_image(stored_lcal[sx], filename_lcal, suffix,
01202                                    stored_sub_headers_lcal[sx], 0./0.));
01203 
01204             // save detector image
01205             KMO_TRY_EXIT_IF_ERROR(
01206                 kmo_dfs_save_image(stored_det_img[sx], filename_det_img, suffix,
01207                                    stored_sub_headers_det_img[sx], 0./0.));
01208         } // for i = nr_devices
01209         } // for a angles
01210 
01211 // Alex: was ist das alles?
01212 //        KMO_TRY_EXIT_IF_NULL(
01213 //                sub_header = cpl_propertylist_new());
01214 //
01215 //        KMO_TRY_EXIT_IF_NULL(
01216 //            extname = kmo_extname_creator(list_frame, -1, EXT_LIST));
01217 //        KMO_TRY_EXIT_IF_ERROR(
01218 //            kmclipm_update_property_string(sub_header,
01219 //                                    EXTNAME,
01220 //                                    extname,
01221 //                                    "FITS extension name"));
01222 //        cpl_free(extname); extname = NULL;
01223 //
01224 //        // save table with wavelengths and
01225 //        KMO_TRY_EXIT_IF_ERROR(
01226 //                kmo_dfs_save_table(arclines, filename_img, sub_header));
01227 
01228         // print which IFUs are not used
01229         kmo_print_unused_ifus(unused_ifus_after, TRUE);
01230     }
01231     KMO_CATCH
01232     {
01233         KMO_CATCH_MSG();
01234         ret_val = -1;
01235     }
01236 
01237     if (last_env != NULL) {
01238         setenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE",last_env,1);
01239     } else {
01240         unsetenv("KMCLIPM_PRIV_RECONSTRUCT_LUT_MODE");
01241     }
01242 
01243     kmo_free_fits_desc(&desc1);
01244     kmo_free_fits_desc(&desc2);
01245     kmo_free_fits_desc(&desc3);
01246     if (unused_ifus_before != NULL) {
01247        kmo_free_unused_ifus(unused_ifus_before); unused_ifus_before = NULL;
01248     }
01249     if (unused_ifus_after != NULL) {
01250        kmo_free_unused_ifus(unused_ifus_after); unused_ifus_after = NULL;
01251     }
01252     cpl_propertylist_delete(main_header); main_header = NULL;
01253     cpl_image_delete(det_lamp_on); det_lamp_on = NULL;
01254     cpl_image_delete(det_lamp_off); det_lamp_off = NULL;
01255     cpl_image_delete(bad_pix_mask); bad_pix_mask = NULL;
01256     cpl_table_delete(arclines); arclines = NULL;
01257     cpl_table_delete(reflines); reflines = NULL;
01258     cpl_free(stored_qc_arc_sat); stored_qc_arc_sat = NULL;
01259     cpl_free(stored_qc_ar_eff); stored_qc_ar_eff = NULL;
01260     cpl_free(stored_qc_ne_eff); stored_qc_ne_eff = NULL;
01261     for (int i = 0; i < nr_devices * nr_angles; i++) {
01262         cpl_image_delete(stored_lcal[i]); stored_lcal[i] = NULL;
01263         cpl_image_delete(stored_det_img[i]); stored_det_img[i] = NULL;
01264         cpl_propertylist_delete(stored_sub_headers_lcal[i]);
01265             stored_sub_headers_lcal[i] = NULL;
01266         cpl_propertylist_delete(stored_sub_headers_det_img[i]);
01267             stored_sub_headers_det_img[i] = NULL;
01268     }
01269     for (int i = 0; i < nr_angles; i++) {
01270         cpl_frameset_delete(angle_frameset[i]); angle_frameset[i] = NULL;
01271     }
01272     for (int i = 0; i < nr_devices; i++) {
01273         cpl_free(filter_ids[i]); filter_ids[i] = NULL;
01274         for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
01275             cpl_table_delete(edge_table[i][j]); edge_table[i][j] = NULL;
01276         }
01277         cpl_free(edge_table[i]); edge_table[i] = NULL;
01278     }
01279     cpl_free(angle_frameset); angle_frameset = NULL;
01280     cpl_free(stored_lcal); stored_lcal = NULL;
01281     cpl_free(stored_det_img); stored_det_img = NULL;
01282     cpl_free(stored_sub_headers_lcal); stored_sub_headers_lcal = NULL;
01283     cpl_free(stored_sub_headers_det_img); stored_sub_headers_det_img = NULL;
01284     cpl_free(filter_ids); filter_ids = NULL;
01285     cpl_free(edge_table); edge_table = NULL;
01286     cpl_free(readmode); readmode = NULL;
01287     cpl_bivector_delete(lines); lines = NULL;
01288     cpl_free(suffix); suffix = NULL;
01289 
01290     return ret_val;
01291 }
01292