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