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