KMOS Pipeline Reference Manual  1.1.3
kmo_dark.c
00001 /* $Id: kmo_dark.c,v 1.19 2013/02/25 10:25:11 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/02/25 10:25:11 $
00024  * $Revision: 1.19 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "kmo_utils.h"
00042 #include "kmo_dfs.h"
00043 #include "kmo_error.h"
00044 #include "kmo_constants.h"
00045 #include "kmo_priv_dark.h"
00046 #include "kmo_priv_functions.h"
00047 #include "kmo_cpl_extensions.h"
00048 #include "kmo_debug.h"
00049 
00050 /*-----------------------------------------------------------------------------
00051  *                          Functions prototypes
00052  *----------------------------------------------------------------------------*/
00053 
00054 static int kmo_dark_create(cpl_plugin *);
00055 static int kmo_dark_exec(cpl_plugin *);
00056 static int kmo_dark_destroy(cpl_plugin *);
00057 static int kmo_dark(cpl_parameterlist *, cpl_frameset *);
00058 
00059 /*-----------------------------------------------------------------------------
00060  *                          Static variables
00061  *----------------------------------------------------------------------------*/
00062 
00063 static char kmo_dark_description[] =
00064 "This recipe calculates the master dark frame.\n"
00065 "\n"
00066 "It is recommended to provide three or more dark exposures to produce a reason-\n"
00067 "able master with associated noise.\n"
00068 "\n"
00069 "BASIC PARAMETERS\n"
00070 "----------------\n"
00071 "--pos_bad_pix_rej\n"
00072 "--neg_bad_pix_rej\n"
00073 "Bad pixels above and below defined positive/negative threshold levels will be\n"
00074 "flagged and output to the BADPIX_DARK frame (which will go into the kmo_flat\n"
00075 "recipe). The number of bad pixels is returned as a QC1 parameter. The two para-\n"
00076 "meters can be used to change these thresholds.\n"
00077 "\n"
00078 "--cmethod\n"
00079 "Following methods of frame combination are available:\n"
00080 "   * 'ksigma' (Default)\n"
00081 "   An iterative sigma clipping. For each position all pixels in the spectrum\n"
00082 "   are examined. If they deviate significantly, they will be rejected according\n"
00083 "   to the conditions:\n"
00084 "       val > mean + stdev * cpos_rej\n"
00085 "   and\n"
00086 "       val < mean - stdev * cneg_rej\n"
00087 "   where --cpos_rej, --cneg_rej and --citer are the corresponding configuration\n"
00088 "   parameters. In the first iteration median and percentile level are used.\n"
00089 "\n"
00090 "   * 'median'\n"
00091 "   At each pixel position the median is calculated.\n"
00092 "\n"
00093 "   * 'average'\n"
00094 "   At each pixel position the average is calculated.\n"
00095 "\n"
00096 "   * 'sum'\n"
00097 "   At each pixel position the sum is calculated.\n"
00098 "\n"
00099 "   * 'min_max'\n"
00100 "   The specified number of minimum and maximum pixel values will be rejected.\n"
00101 "   --cmax and --cmin apply to this method.\n"
00102 "\n"
00103 "--file_extension"
00104 "Set this parameter to TRUE if the EXPTIME keyword should be appended to\n"
00105 "the output filenames.\n"
00106 "\n"
00107 "ADVANCED PARAMETERS\n"
00108 "-------------------\n"
00109 "--cpos_rej\n"
00110 "--cneg_rej\n"
00111 "--citer\n"
00112 "see --cmethod='ksigma'\n"
00113 "\n"
00114 "--cmax\n"
00115 "--cmin\n"
00116 "see --cmethod='min_max'\n"
00117 "\n"
00118 "-------------------------------------------------------------------------------\n"
00119 "Input files:\n"
00120 "\n"
00121 "   DO                   KMOS                                                   \n"
00122 "   category             Type   Explanation                     Required #Frames\n"
00123 "   --------             -----  -----------                     -------- -------\n"
00124 "   DARK                 RAW    Dark exposures                     Y       1-n  \n"
00125 "                               (at least 3 frames recommended)                 \n"
00126 "\n"
00127 "Output files:\n"
00128 "\n"
00129 "   DO                   KMOS\n"
00130 "   category             Type   Explanation\n"
00131 "   --------             -----  -----------\n"
00132 "   MASTER_DARK          F2D    Calculated master dark frames\n"
00133 "\n"
00134 "   BADPIXEL_DARK        B2D    Associated badpixel frames\n"
00135 "\n"
00136 "-------------------------------------------------------------------------------"
00137 "\n";
00138 
00139 /*-----------------------------------------------------------------------------
00140  *                              Functions code
00141  *----------------------------------------------------------------------------*/
00142 
00159 int cpl_plugin_get_info(cpl_pluginlist *list)
00160 {
00161     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00162     cpl_plugin *plugin = &recipe->interface;
00163 
00164     cpl_plugin_init(plugin,
00165                         CPL_PLUGIN_API,
00166                         KMOS_BINARY_VERSION,
00167                         CPL_PLUGIN_TYPE_RECIPE,
00168                         "kmo_dark",
00169                         "Create master dark frame & bad pixel mask",
00170                         kmo_dark_description,
00171                         "Alex Agudo Berbel",
00172                         "agudo@mpe.mpg.de",
00173                         kmos_get_license(),
00174                         kmo_dark_create,
00175                         kmo_dark_exec,
00176                         kmo_dark_destroy);
00177 
00178     cpl_pluginlist_append(list, plugin);
00179 
00180     return 0;
00181 }
00182 
00190 static int kmo_dark_create(cpl_plugin *plugin)
00191 {
00192     cpl_recipe *recipe;
00193     cpl_parameter *p;
00194 
00195     /* Check that the plugin is part of a valid recipe */
00196     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00197         recipe = (cpl_recipe *)plugin;
00198     else
00199         return -1;
00200 
00201     /* Create the parameters list in the cpl_recipe object */
00202     recipe->parameters = cpl_parameterlist_new();
00203 
00204     /* Fill the parameters list */
00205 
00206     /* --pos_bad_pix_rej */
00207     p = cpl_parameter_new_value("kmos.kmo_dark.pos_bad_pix_rej",
00208                                 CPL_TYPE_DOUBLE,
00209                                 "The positive rejection threshold for "
00210                                 "bad pixels",
00211                                 "kmos.kmo_dark",
00212                                 50.0);
00213     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pos_bad_pix_rej");
00214     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00215     cpl_parameterlist_append(recipe->parameters, p);
00216 
00217     /* --neg_bad_pix_rej */
00218     p = cpl_parameter_new_value("kmos.kmo_dark.neg_bad_pix_rej",
00219                                 CPL_TYPE_DOUBLE,
00220                                 "The negative rejection threshold for "
00221                                 "bad pixels",
00222                                 "kmos.kmo_dark",
00223                                 50.0);
00224     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neg_bad_pix_rej");
00225     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00226     cpl_parameterlist_append(recipe->parameters, p);
00227 
00228     /* --file_extension */
00229     p = cpl_parameter_new_value("kmos.kmo_dark.file_extension",
00230                                 CPL_TYPE_BOOL,
00231                                 "Controls if EXPTIME keyword should be appended "
00232                                 "to product filenames.",
00233                                 "kmos.kmo_dark",
00234                                 FALSE);
00235     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "file_extension");
00236     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00237     cpl_parameterlist_append(recipe->parameters, p);
00238 
00239     return kmo_combine_pars_create(recipe->parameters,
00240                                    "kmos.kmo_dark",
00241                                    DEF_REJ_METHOD,
00242                                    FALSE);
00243 }
00244 
00250 static int kmo_dark_exec(cpl_plugin *plugin)
00251 {
00252     cpl_recipe  *recipe;
00253 
00254     /* Get the recipe out of the plugin */
00255     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00256         recipe = (cpl_recipe *)plugin;
00257     else return -1;
00258 
00259     return kmo_dark(recipe->parameters, recipe->frames);
00260 }
00261 
00267 static int kmo_dark_destroy(cpl_plugin *plugin)
00268 {
00269     cpl_recipe *recipe;
00270 
00271     /* Get the recipe out of the plugin */
00272     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00273         recipe = (cpl_recipe *)plugin;
00274     else return -1 ;
00275 
00276     cpl_parameterlist_delete(recipe->parameters);
00277     return 0 ;
00278 }
00279 
00290 static int kmo_dark(cpl_parameterlist *parlist, cpl_frameset *frameset)
00291 {
00292     cpl_imagelist    *detector_in_window       = NULL;
00293 
00294     cpl_image        *img_in_window            = NULL,
00295                      *combined_data            = NULL,
00296                      *combined_data_window     = NULL,
00297                      *combined_noise           = NULL,
00298                      *combined_noise_window    = NULL,
00299                      *bad_pix_mask             = NULL,
00300                      *bad_pix_mask_window      = NULL;
00301 
00302     cpl_frame        *frame             = NULL;
00303 
00304     int              ret_val             = 0,
00305                      nr_devices          = 0,
00306                      i                   = 0,
00307                      cmax                = 0,
00308                      cmin                = 0,
00309                      citer               = 0,
00310                      nx                  = 0,
00311                      ny                  = 0,
00312                      nx_orig             = 0,
00313                      ny_orig             = 0,
00314                      nz                  = 0,
00315                      ndit                = 0,
00316                      file_extension      = FALSE;
00317 
00318     double           cpos_rej            = 0.0,
00319                      cneg_rej            = 0.0,
00320                      exptime             = 0.0,
00321                      gain                = 0.0,
00322                      pos_bad_pix_rej     = 0.0,
00323                      neg_bad_pix_rej     = 0.0,
00324                      qc_dark             = 0.0,
00325                      qc_dark_median      = 0.0,
00326                      qc_readnoise        = 0.0,
00327                      qc_readnoise_median = 0.0,
00328                      qc_bad_pix_num      = 0.0;
00329 
00330     const char       *cmethod            = NULL,
00331                      *my_method          = NULL;
00332 
00333     char             *filename           = NULL,
00334                      *filename_bad       = NULL,
00335                      *extname            = NULL;
00336 
00337     cpl_propertylist *main_header        = NULL,
00338                      *sub_header         = NULL;
00339 
00340     main_fits_desc   desc1, desc2;
00341 
00342     char             do_mode[256];
00343 
00344     KMO_TRY
00345     {
00346         kmo_init_fits_desc(&desc1);
00347         kmo_init_fits_desc(&desc2);
00348 
00349         // --- check inputs ---
00350         KMO_TRY_ASSURE((parlist != NULL) &&
00351                        (frameset != NULL),
00352                        CPL_ERROR_NULL_INPUT,
00353                        "Not all input data is provided!");
00354 
00355         if (cpl_frameset_count_tags(frameset, DARK) < 3) {
00356             cpl_msg_warning(cpl_func, "It is recommended to provide at least "
00357                                       "3 DARK frames!");
00358         }
00359 
00360         if (cpl_frameset_count_tags(frameset, DARK) >= 1) {
00361             strcpy(do_mode, DARK);
00362         } else {
00363             strcpy(do_mode, "0");
00364         }
00365 
00366         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_dark") == 1,
00367                        CPL_ERROR_ILLEGAL_INPUT,
00368                        "Cannot identify RAW and CALIB frames!");
00369 
00370         // --- get parameters ---
00371         cpl_msg_info("", "--- Parameter setup for kmo_dark ----------");
00372 
00373         pos_bad_pix_rej = kmo_dfs_get_parameter_double(parlist,
00374                                            "kmos.kmo_dark.pos_bad_pix_rej");
00375         KMO_TRY_CHECK_ERROR_STATE();
00376         KMO_TRY_EXIT_IF_ERROR(
00377             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_dark.pos_bad_pix_rej"));
00378 
00379         neg_bad_pix_rej = kmo_dfs_get_parameter_double(parlist,
00380                                            "kmos.kmo_dark.neg_bad_pix_rej");
00381         KMO_TRY_CHECK_ERROR_STATE();
00382         KMO_TRY_EXIT_IF_ERROR(
00383             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_dark.neg_bad_pix_rej"));
00384 
00385         file_extension = kmo_dfs_get_parameter_bool(parlist,
00386                                                         "kmos.kmo_dark.file_extension");
00387         KMO_TRY_CHECK_ERROR_STATE();
00388         KMO_TRY_EXIT_IF_ERROR(
00389            kmo_dfs_print_parameter_help(parlist, "kmos.kmo_dark.file_extension"));
00390 
00391         KMO_TRY_ASSURE((file_extension == TRUE) ||
00392                        (file_extension == FALSE),
00393                        CPL_ERROR_ILLEGAL_INPUT,
00394                        "extension must be TRUE or FALSE!");
00395 
00396         KMO_TRY_EXIT_IF_ERROR(
00397             kmo_combine_pars_load(parlist,
00398                                   "kmos.kmo_dark",
00399                                   &cmethod,
00400                                   &cpos_rej,
00401                                   &cneg_rej,
00402                                   &citer,
00403                                   &cmin,
00404                                   &cmax,
00405                                   FALSE));
00406         
00407         cpl_msg_info("", "-------------------------------------------");
00408         cpl_msg_info("", "Detected instrument setup:");
00409         cpl_msg_info("", "   not checked here");
00410         cpl_msg_info("", "-------------------------------------------");
00411         cpl_msg_info("", "IFU status before processing:");
00412         cpl_msg_info("", "   not checked here");
00413         cpl_msg_info("", "-------------------------------------------");
00414 
00415         KMO_TRY_EXIT_IF_NULL(
00416             frame = kmo_dfs_get_frame(frameset, do_mode));
00417 
00418         i = 0;
00419         while (frame != NULL) {
00420              main_header = kmclipm_propertylist_load(
00421                                               cpl_frame_get_filename(frame), 0);
00422 
00423             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00424                 cpl_msg_error(cpl_func, "File '%s' not found",
00425                                                  cpl_frame_get_filename(frame));
00426                 KMO_TRY_CHECK_ERROR_STATE();
00427             }
00428 
00429             if (i == 0) {
00430                 exptime = cpl_propertylist_get_double(main_header, EXPTIME);
00431 
00432                 KMO_TRY_CHECK_ERROR_STATE("EXPTIME keyword in main header "
00433                                           "missing!");
00434 
00435                 ndit = cpl_propertylist_get_int(main_header, NDIT);
00436 
00437                 KMO_TRY_CHECK_ERROR_STATE("NDIT keyword in main header "
00438                                           "missing!");
00439 
00440                 if (file_extension) {
00441                     // delete trailing zeros (if zero right after decimal point, delete point as well)
00442                     char *exptimeStr = cpl_sprintf("%g", exptime);
00443                     char *p = 0;
00444                     for(p=exptimeStr; *p; ++p) {
00445                         if('.' == *p) {
00446                             while(*++p);
00447                             while('0'==*--p) *p = '\0';
00448                             if(*p == '.') *p = '\0';
00449                             break;
00450                         }
00451                     }
00452 
00453                     filename = cpl_sprintf("%s_%s", MASTER_DARK, exptimeStr);
00454                     filename_bad = cpl_sprintf("%s_%s", BADPIXEL_DARK, exptimeStr);
00455                     cpl_free(exptimeStr); exptimeStr = NULL;
00456                 } else {
00457                     filename = cpl_sprintf("%s", MASTER_DARK);
00458                     filename_bad = cpl_sprintf("%s", BADPIXEL_DARK);
00459                 }
00460 
00461 
00462                 desc1 = kmo_identify_fits_header(
00463                             cpl_frame_get_filename(frame));
00464 
00465                 KMO_TRY_CHECK_ERROR_STATE_MSG("First fits file doesn't seem to "
00466                                               "be in KMOS-format!");
00467 
00468                 KMO_TRY_ASSURE(desc1.fits_type == raw_fits,
00469                                CPL_ERROR_ILLEGAL_INPUT,
00470                                "First input file hasn't correct data type "
00471                                "(must be a raw, unprocessed file)!");
00472             } else {
00473 
00474                 desc2 = kmo_identify_fits_header(
00475                             cpl_frame_get_filename(frame));
00476                 KMO_TRY_CHECK_ERROR_STATE_MSG("Fits file doesn't seem to be "
00477                                               "in KMOS-format!");
00478 
00479                 KMO_TRY_ASSURE(desc2.fits_type == raw_fits,
00480                                CPL_ERROR_ILLEGAL_INPUT,
00481                                "An input file hasn't correct data type "
00482                                "(must be a raw, unprocessed file)!");
00483 
00484                 kmo_free_fits_desc(&desc2);
00485             }
00486 
00487             // check if all lamps are off (flat and arc lamp)
00488             KMO_TRY_ASSURE(((kmo_check_lamp(main_header, INS_LAMP1_ST) == FALSE) &&
00489                             (kmo_check_lamp(main_header, INS_LAMP2_ST) == FALSE) &&
00490                             (kmo_check_lamp(main_header, INS_LAMP3_ST) == FALSE) &&
00491                             (kmo_check_lamp(main_header, INS_LAMP4_ST) == FALSE)) ||
00492                            (((kmo_check_lamp(main_header, INS_LAMP1_ST) == TRUE) ||
00493                              (kmo_check_lamp(main_header, INS_LAMP2_ST) == TRUE) ||
00494                              (kmo_check_lamp(main_header, INS_LAMP3_ST) == TRUE) ||
00495                              (kmo_check_lamp(main_header, INS_LAMP4_ST) == TRUE)) &&
00496                             (strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT1 ID"), "Block") == 0) &&
00497                             (strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT2 ID"), "Block") == 0) &&
00498                             (strcmp(cpl_propertylist_get_string(main_header, "ESO INS FILT3 ID"), "Block") == 0)),
00499                            CPL_ERROR_ILLEGAL_INPUT,
00500                            "All lamps must be switched off for DARK frames!");
00501 
00502             // check if EXPTIME and NDIT are the same for all frames
00503             if (cpl_propertylist_get_double(main_header, EXPTIME) != exptime) {
00504                 cpl_msg_warning(cpl_func,
00505                                 "EXPTIME isn't the same for all "
00506                                 "frames: (is %g and %g). Proceeding anyway...",
00507                                 cpl_propertylist_get_double(main_header,
00508                                                             EXPTIME),
00509                                 exptime);
00510             }
00511 
00512             if (cpl_propertylist_get_int(main_header, NDIT) != ndit) {
00513                 cpl_msg_warning(cpl_func,
00514                                 "NDIT isn't the same for all "
00515                                 "frames: (is %d and %d). Proceeding anyway...",
00516                                 cpl_propertylist_get_int(main_header, NDIT),
00517                                 ndit);
00518             }
00519 
00520             // get next DARK frame
00521             frame = kmo_dfs_get_frame(frameset, NULL);
00522             KMO_TRY_CHECK_ERROR_STATE();
00523 
00524             cpl_propertylist_delete(main_header); main_header = NULL;
00525             i++;
00526         }
00527 
00528         // --- load, update & save primary header ---
00529         KMO_TRY_EXIT_IF_NULL(
00530             frame = kmo_dfs_get_frame(frameset, do_mode));
00531 
00532         KMO_TRY_EXIT_IF_ERROR(
00533             kmo_dfs_save_main_header(frameset, filename, "", frame,
00534                                      NULL, parlist, cpl_func));
00535 
00536         KMO_TRY_EXIT_IF_ERROR(
00537             kmo_dfs_save_main_header(frameset, filename_bad, "", frame,
00538                                      NULL, parlist, cpl_func));
00539 
00540         // --- load data ---
00541         nr_devices = desc1.nr_ext;
00542 
00543         my_method = cmethod;
00544         if ((cpl_frameset_count_tags(frameset, DARK) == 1) ||
00545             (cpl_frameset_count_tags(frameset, COMMANDLINE) == 1)) {
00546             cpl_msg_warning(cpl_func, "cmethod is changed to 'average' "
00547                             "since there is only one input frame!");
00548 
00549             my_method = "average";
00550         }
00551 
00552         // get size of input frame
00553         KMO_TRY_EXIT_IF_NULL(
00554             img_in_window = kmo_dfs_load_image(frameset, do_mode, 1, FALSE, FALSE, NULL));
00555         nx_orig = cpl_image_get_size_x(img_in_window);
00556         ny_orig = cpl_image_get_size_y(img_in_window);
00557         cpl_image_delete(img_in_window); img_in_window = NULL;
00558 
00559         KMO_TRY_ASSURE((nx_orig > 2*KMOS_BADPIX_BORDER) &&
00560                        (ny_orig > 2*KMOS_BADPIX_BORDER),
00561                        CPL_ERROR_ILLEGAL_INPUT,
00562                        "Input frames must have a height and width of at "
00563                        "least 9 pixels!");
00564 
00565         // --- loop through all detectors ---
00566         for (i = 1; i <= nr_devices; i++) {
00567             cpl_msg_info("","Processing detector No. %d", i);
00568 
00569             KMO_TRY_EXIT_IF_NULL(
00570                 detector_in_window = cpl_imagelist_new());
00571 
00572             KMO_TRY_EXIT_IF_NULL(
00573                 sub_header = kmo_dfs_load_sub_header(frameset, do_mode,
00574                                                      i, FALSE));
00575 
00576             // load data of device i of all DARK frames into an imagelist
00577             KMO_TRY_EXIT_IF_NULL(
00578                 img_in_window = kmo_dfs_load_image_window(
00579                                        frameset, do_mode, i, FALSE,
00580                                        KMOS_BADPIX_BORDER+1,
00581                                        KMOS_BADPIX_BORDER+1,
00582                                        nx_orig-KMOS_BADPIX_BORDER,
00583                                        ny_orig-KMOS_BADPIX_BORDER,
00584                                        FALSE, NULL));
00585 
00586             nx = cpl_image_get_size_x(img_in_window);
00587             ny = cpl_image_get_size_y(img_in_window);
00588 
00589             nz = 0;
00590             while (img_in_window != NULL) {
00591                 cpl_imagelist_set(detector_in_window, img_in_window, nz);
00592                 KMO_TRY_CHECK_ERROR_STATE();
00593 
00594                 // load same extension of next DARK frame
00595                 img_in_window = kmo_dfs_load_image_window(
00596                                             frameset, NULL, i, FALSE,
00597                                             KMOS_BADPIX_BORDER+1,
00598                                             KMOS_BADPIX_BORDER+1,
00599                                             nx_orig-KMOS_BADPIX_BORDER,
00600                                             ny_orig-KMOS_BADPIX_BORDER,
00601                                             FALSE, NULL);
00602                 KMO_TRY_CHECK_ERROR_STATE();
00603 
00604                 if (img_in_window != NULL) {
00605                     KMO_TRY_ASSURE((nx == cpl_image_get_size_x(img_in_window)) &&
00606                                    (ny == cpl_image_get_size_y(img_in_window)),
00607                                    CPL_ERROR_ILLEGAL_INPUT,
00608                                    "Not all input frames have the "
00609                                    "same dimensions!");
00610                 }
00611                 nz++;
00612             }
00613 
00614             // combine imagelist (data only) and create noise
00615             KMO_TRY_EXIT_IF_ERROR(
00616                 kmclipm_combine_frames(detector_in_window,
00617                                        NULL,
00618                                        NULL,
00619                                        my_method,
00620                                        cpos_rej,
00621                                        cneg_rej,
00622                                        citer,
00623                                        cmax,
00624                                        cmin,
00625                                        &combined_data_window,
00626                                        &combined_noise_window,
00627                                        -1.0));
00628 
00629             if (kmclipm_omit_warning_one_slice > 10) {
00630                 cpl_msg_warning(cpl_func, "Previous warning (number of "
00631                                           "identified slices) occured %d times.",
00632                                 kmclipm_omit_warning_one_slice);
00633                 kmclipm_omit_warning_one_slice = FALSE;
00634             }
00635 
00636             // calculate preliminary mean and stdev to create the bad pixel mask
00637             qc_dark = cpl_image_get_mean(combined_data_window);
00638             KMO_TRY_CHECK_ERROR_STATE();
00639 
00640             if (nz > 2) {
00641                 qc_readnoise = cpl_image_get_mean(combined_noise_window);
00642                 KMO_TRY_CHECK_ERROR_STATE();
00643 
00644                 KMO_TRY_ASSURE(qc_readnoise != 0.0,
00645                                CPL_ERROR_ILLEGAL_INPUT,
00646                                "All frames of detector %i are exactly "
00647                                "the same!", i);
00648             } else if (nz == 2) {
00649                 qc_readnoise = cpl_image_get_stdev(combined_noise_window);
00650                 KMO_TRY_CHECK_ERROR_STATE();
00651 
00652                 KMO_TRY_ASSURE(qc_readnoise != 0.0,
00653                                CPL_ERROR_ILLEGAL_INPUT,
00654                                "All frames of detector %i are exactly "
00655                                "the same!", i);
00656             } else if (nz == 1) {
00657                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00658                 KMO_TRY_CHECK_ERROR_STATE();
00659 
00660                 KMO_TRY_ASSURE(qc_readnoise != 0.0,
00661                                CPL_ERROR_ILLEGAL_INPUT,
00662                                "The detector frame %d seems to be uniform!", i);
00663             } else {
00664                 KMO_TRY_ASSURE(1 == 0,
00665                                CPL_ERROR_ILLEGAL_INPUT,
00666                                "detector frame must have at least one frame!");
00667             }
00668 
00669             // create bad-pixel-mask
00670             qc_bad_pix_num = kmo_create_bad_pix_dark(combined_data_window,
00671                                                      qc_dark,
00672                                                      qc_readnoise,
00673                                                      pos_bad_pix_rej,
00674                                                      neg_bad_pix_rej,
00675                                                      &bad_pix_mask_window);
00676             KMO_TRY_CHECK_ERROR_STATE();
00677 
00678             KMO_TRY_EXIT_IF_ERROR(
00679                 kmclipm_update_property_int(sub_header,
00680                                             QC_NR_BAD_PIX,
00681                                             qc_bad_pix_num,
00682                                             "[] nr. of bad pixels"));
00683 
00684             //
00685             // calculate QC.DARK, QC.READNOISE, QC.DARK.MEDIAN,
00686             // QC.READNOISE.MEDIAN, QC.DARKCUR
00687 
00688             // badpixels from combined_data_window are already rejected in
00689             // kmo_create_bad_pix_dark()
00690             KMO_TRY_EXIT_IF_ERROR(
00691                 kmo_image_reject_from_mask(combined_noise_window,
00692                                            bad_pix_mask_window));
00693 
00694             qc_dark = cpl_image_get_mean(combined_data_window);
00695             KMO_TRY_CHECK_ERROR_STATE();
00696 
00697             // calculate mean and stddev of combined frames (with rejection)
00698             if (nz > 2) {
00699                 qc_readnoise = cpl_image_get_mean(combined_noise_window) * sqrt(nz);
00700             } else if (nz == 2) {
00701                 qc_readnoise =
00702                      cpl_image_get_stdev(combined_noise_window) * sqrt(2.0);
00703             } else if (nz == 1) {
00704                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00705             } else {
00706                 KMO_TRY_ASSURE(1 == 0,
00707                         CPL_ERROR_ILLEGAL_INPUT,
00708                         "detector frame must have at least one frame!");
00709             }
00710             KMO_TRY_CHECK_ERROR_STATE();
00711 
00712             qc_dark_median = cpl_image_get_median(combined_data_window);
00713             KMO_TRY_CHECK_ERROR_STATE();
00714 
00715             if (nz > 2) {
00716                 qc_readnoise_median =
00717                         cpl_image_get_median(combined_noise_window) * sqrt(nz);
00718             } else if (nz == 2) {
00719                 qc_readnoise_median =
00720                          kmo_image_get_stdev_median(combined_noise_window) *
00721                                                                   sqrt(2.0);
00722             } else if (nz == 1) {
00723                 qc_readnoise_median =
00724                            kmo_image_get_stdev_median(combined_data_window);
00725             } else {
00726                 KMO_TRY_ASSURE(1 == 0,
00727                         CPL_ERROR_ILLEGAL_INPUT,
00728                         "detector frame must have at least one frame!");
00729             }
00730             KMO_TRY_CHECK_ERROR_STATE();
00731 
00732             KMO_TRY_EXIT_IF_ERROR(
00733                 kmclipm_update_property_double(sub_header,
00734                                                QC_DARK,
00735                                                qc_dark,
00736                                               "[adu] mean of master dark"));
00737             KMO_TRY_EXIT_IF_ERROR(
00738                 kmclipm_update_property_double(sub_header,
00739                                                QC_READNOISE,
00740                                                qc_readnoise,
00741                                         "[adu] mean noise of master dark"));
00742             KMO_TRY_EXIT_IF_ERROR(
00743                 kmclipm_update_property_double(sub_header,
00744                                                QC_DARK_MEDIAN,
00745                                                qc_dark_median,
00746                                             "[adu] median of master dark"));
00747             KMO_TRY_EXIT_IF_ERROR(
00748                 kmclipm_update_property_double(sub_header,
00749                                                QC_READNOISE_MEDIAN,
00750                                                qc_readnoise_median,
00751                                       "[adu] median noise of master dark"));
00752 
00753             // load gain
00754             gain = kmo_dfs_get_property_double(sub_header, GAIN);
00755             KMO_TRY_CHECK_ERROR_STATE_MSG(
00756                                  "GAIN-keyword in fits-header is missing!");
00757 
00758             KMO_TRY_EXIT_IF_ERROR(
00759                 kmclipm_update_property_double(sub_header,
00760                                                QC_DARK_CURRENT,
00761                                                qc_dark / exptime / gain,
00762                                                "[e-/s] dark current"));
00763 
00764             // save dark frame
00765             KMO_TRY_EXIT_IF_NULL(
00766                 extname = kmo_extname_creator(detector_frame, i, EXT_DATA));
00767             KMO_TRY_EXIT_IF_ERROR(
00768                 kmclipm_update_property_string(sub_header, EXTNAME,
00769                                                extname,
00770                                                "FITS extension name"));
00771             cpl_free(extname); extname = NULL;
00772 
00773             KMO_TRY_EXIT_IF_NULL(
00774                 combined_data = kmo_add_bad_pix_border(combined_data_window,
00775                                                        TRUE));
00776 
00777             KMO_TRY_EXIT_IF_ERROR(
00778                 kmo_dfs_save_image(combined_data, filename, "", sub_header, 0./0.));
00779 
00780             // save noise frame
00781             KMO_TRY_EXIT_IF_NULL(
00782                 extname = kmo_extname_creator(detector_frame, i, EXT_NOISE));
00783             KMO_TRY_EXIT_IF_ERROR(
00784                 kmclipm_update_property_string(sub_header, EXTNAME,
00785                                                extname,
00786                                                "FITS extension name"));
00787             cpl_free(extname); extname = NULL;
00788 
00789             KMO_TRY_EXIT_IF_NULL(
00790                 combined_noise = kmo_add_bad_pix_border(combined_noise_window,
00791                                                         TRUE));
00792 
00793             KMO_TRY_EXIT_IF_ERROR(
00794                 kmo_dfs_save_image(combined_noise, filename, "", sub_header, 0./0.));
00795 
00796             // save bad_pix frame
00797             KMO_TRY_EXIT_IF_NULL(
00798                 extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX));
00799             KMO_TRY_EXIT_IF_ERROR(
00800                 kmclipm_update_property_string(sub_header, EXTNAME,
00801                                                extname,
00802                                                "FITS extension name"));
00803             cpl_free(extname); extname = NULL;
00804 
00805             KMO_TRY_EXIT_IF_NULL(
00806                 bad_pix_mask = kmo_add_bad_pix_border(bad_pix_mask_window,
00807                                                       FALSE));
00808 
00809             KMO_TRY_EXIT_IF_ERROR(
00810                 kmo_dfs_save_image(bad_pix_mask, filename_bad, "", sub_header, 0.));
00811 
00812             // free memory
00813             cpl_propertylist_delete(sub_header); sub_header = NULL;
00814             cpl_imagelist_delete(detector_in_window); detector_in_window = NULL;
00815             cpl_image_delete(combined_data); combined_data = NULL;
00816             cpl_image_delete(combined_data_window); combined_data_window = NULL;
00817             cpl_image_delete(combined_noise); combined_noise = NULL;
00818             cpl_image_delete(combined_noise_window); combined_noise_window = NULL;
00819             cpl_image_delete(bad_pix_mask); bad_pix_mask = NULL;
00820             cpl_image_delete(bad_pix_mask_window); bad_pix_mask_window = NULL;
00821         } // for i = [1, nr_devices]
00822 
00823         cpl_msg_info("", "-------------------------------------------");
00824         cpl_msg_info("", "IFU status after processing:");
00825         cpl_msg_info("", "   not checked here");
00826         cpl_msg_info("", "-------------------------------------------");
00827     }
00828     KMO_CATCH
00829     {
00830         KMO_CATCH_MSG();
00831 
00832 //        if (desc2.sub_desc != NULL) {
00833             kmo_free_fits_desc(&desc2);
00834 //        }
00835 
00836         ret_val = -1;
00837     }
00838 
00839     kmo_free_fits_desc(&desc1);
00840     cpl_free(filename); filename = NULL;
00841     cpl_free(filename_bad); filename_bad = NULL;
00842     cpl_propertylist_delete(main_header); main_header = NULL;
00843     cpl_propertylist_delete(sub_header); sub_header = NULL;
00844     cpl_imagelist_delete(detector_in_window); detector_in_window = NULL;
00845     cpl_image_delete(combined_data); combined_data = NULL;
00846     cpl_image_delete(combined_data_window); combined_data_window = NULL;
00847     cpl_image_delete(combined_noise); combined_noise = NULL;
00848     cpl_image_delete(combined_noise_window); combined_noise_window = NULL;
00849     cpl_image_delete(bad_pix_mask); bad_pix_mask = NULL;
00850     cpl_image_delete(bad_pix_mask_window); bad_pix_mask_window = NULL;
00851 
00852     return ret_val;
00853 }
00854