KMOS Pipeline Reference Manual  1.3.7
kmos_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 "kmos_pfits.h"
00035 #include "kmo_dfs.h"
00036 #include "kmo_error.h"
00037 #include "kmo_constants.h"
00038 #include "kmo_priv_dark.h"
00039 #include "kmo_priv_combine.h"
00040 #include "kmo_priv_functions.h"
00041 #include "kmo_cpl_extensions.h"
00042 #include "kmo_debug.h"
00043 
00044 /*-----------------------------------------------------------------------------
00045  *                          Functions prototypes
00046  *----------------------------------------------------------------------------*/
00047 
00048 static int kmos_dark_check_inputs(cpl_frameset *, int *, int *, int *, int *,
00049         double *);
00050 
00051 static int kmos_dark_create(cpl_plugin *);
00052 static int kmos_dark_exec(cpl_plugin *);
00053 static int kmos_dark_destroy(cpl_plugin *);
00054 static int kmos_dark(cpl_parameterlist *, cpl_frameset *);
00055 
00056 /*-----------------------------------------------------------------------------
00057  *                          Static variables
00058  *----------------------------------------------------------------------------*/
00059 
00060 static char kmos_dark_description[] =
00061 "This recipe calculates the master dark frame.\n"
00062 "\n"
00063 "It is recommended to provide three or more dark exposures to produce a\n"
00064 "reasonable master with associated noise.\n"
00065 "\n"
00066 "BASIC PARAMETERS\n"
00067 "----------------\n"
00068 "--pos_bad_pix_rej\n"
00069 "--neg_bad_pix_rej\n"
00070 "Bad pixels above and below defined positive/negative threshold levels will\n"
00071 "be flagged and output to the BADPIX_DARK frame.\n"
00072 "The number of bad pixels is returned as a QC1 parameter.\n"
00073 "The two parameters can be used to change these thresholds.\n"
00074 "\n"
00075 "--cmethod\n"
00076 "Following methods of frame combination are available:\n"
00077 "   * 'ksigma' (Default)\n"
00078 "       An iterative sigma clipping. For each position all pixels in the\n"
00079 "       spectrum are examined. If they deviate significantly, they will be\n"
00080 "       rejected according to the conditions:\n"
00081 "           val > mean + stdev * cpos_rej\n"
00082 "       and\n"
00083 "           val < mean - stdev * cneg_rej\n"
00084 "       where --cpos_rej, --cneg_rej and --citer are the wished parameters\n"
00085 "       In the first iteration median and percentile level are used.\n"
00086 "   * 'median'\n"
00087 "       At each pixel position the median is calculated.\n"
00088 "   * 'average'\n"
00089 "       At each pixel position the average is calculated.\n"
00090 "   * 'sum'\n"
00091 "       At each pixel position the sum is calculated.\n"
00092 "   * 'min_max'\n"
00093 "       The specified number of min and max pixel values will be rejected.\n"
00094 "       --cmax and --cmin apply to this method.\n"
00095 "\n"
00096 "--file_extension\n"
00097 "Set this parameter to TRUE if the EXPTIME keyword should be appended to\n"
00098 "the output filenames.\n"
00099 "\n"
00100 "ADVANCED PARAMETERS\n"
00101 "-------------------\n"
00102 "--cpos_rej\n"
00103 "--cneg_rej\n"
00104 "--citer\n"
00105 "   see --cmethod='ksigma'\n"
00106 "--cmax\n"
00107 "--cmin\n"
00108 "   see --cmethod='min_max'\n"
00109 "\n"
00110 "---------------------------------------------------------------------------\n"
00111 "Input files:\n"
00112 "   DO CATG          Type   Explanation                     Required #Frames\n"
00113 "   -------          -----  -----------                     -------- -------\n"
00114 "   DARK             RAW    Dark exposures                     Y       1-n  \n"
00115 "                           (at least 3 frames recommended)                 \n"
00116 "\n"
00117 "Output files:\n"
00118 "   DO CATG          Type   Explanation\n"
00119 "   -------          -----  -----------\n"
00120 "   MASTER_DARK      F2D    Calculated master dark frames\n"
00121 "   BADPIXEL_DARK    B2D    Associated badpixel frames\n"
00122 "---------------------------------------------------------------------------"
00123 "\n";
00124 
00125 /*----------------------------------------------------------------------------*/
00129 /*----------------------------------------------------------------------------*/
00130 
00133 /*-----------------------------------------------------------------------------
00134  *                              Functions code
00135  *----------------------------------------------------------------------------*/
00136 
00137 /*----------------------------------------------------------------------------*/
00146 /*----------------------------------------------------------------------------*/
00147 int cpl_plugin_get_info(cpl_pluginlist *list)
00148 {
00149     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00150     cpl_plugin *plugin = &recipe->interface;
00151 
00152     cpl_plugin_init(plugin,
00153             CPL_PLUGIN_API,
00154             KMOS_BINARY_VERSION,
00155             CPL_PLUGIN_TYPE_RECIPE,
00156             "kmos_dark",
00157             "Create master dark frame & bad pixel mask",
00158             kmos_dark_description,
00159             "Alex Agudo Berbel, Yves Jung",
00160             "usd-help@eso.org",
00161             kmos_get_license(),
00162             kmos_dark_create,
00163             kmos_dark_exec,
00164             kmos_dark_destroy);
00165 
00166     cpl_pluginlist_append(list, plugin);
00167 
00168     return 0;
00169 }
00170 
00171 /*----------------------------------------------------------------------------*/
00179 /*----------------------------------------------------------------------------*/
00180 static int kmos_dark_create(cpl_plugin *plugin)
00181 {
00182     cpl_recipe *recipe;
00183     cpl_parameter *p;
00184 
00185     /* Check that the plugin is part of a valid recipe */
00186     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00187         recipe = (cpl_recipe *)plugin;
00188     else
00189         return -1;
00190 
00191     /* Create the parameters list in the cpl_recipe object */
00192     recipe->parameters = cpl_parameterlist_new();
00193 
00194     /* Fill the parameters list */
00195 
00196     /* --pos_bad_pix_rej */
00197     p = cpl_parameter_new_value("kmos.kmos_dark.pos_bad_pix_rej", 
00198             CPL_TYPE_DOUBLE, "The positive rejection threshold for bad pixels",
00199             "kmos.kmos_dark", 50.0);
00200     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pos_bad_pix_rej");
00201     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00202     cpl_parameterlist_append(recipe->parameters, p);
00203 
00204     /* --neg_bad_pix_rej */
00205     p = cpl_parameter_new_value("kmos.kmos_dark.neg_bad_pix_rej",
00206             CPL_TYPE_DOUBLE, "The negative rejection threshold for bad pixels",
00207             "kmos.kmos_dark", 50.0);
00208     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neg_bad_pix_rej");
00209     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00210     cpl_parameterlist_append(recipe->parameters, p);
00211 
00212     /* --file_extension */
00213     p = cpl_parameter_new_value("kmos.kmos_dark.file_extension", CPL_TYPE_BOOL,
00214             "Controls if EXPTIME should be appended to product filenames",
00215             "kmos.kmos_dark", FALSE);
00216     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "file_extension");
00217     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00218     cpl_parameterlist_append(recipe->parameters, p);
00219 
00220     return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_dark", 
00221             DEF_REJ_METHOD, FALSE);
00222 }
00223 
00224 /*----------------------------------------------------------------------------*/
00230 /*----------------------------------------------------------------------------*/
00231 static int kmos_dark_exec(cpl_plugin *plugin)
00232 {
00233     cpl_recipe  *recipe;
00234 
00235     /* Get the recipe out of the plugin */
00236     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00237         recipe = (cpl_recipe *)plugin;
00238     else return -1;
00239 
00240     return kmos_dark(recipe->parameters, recipe->frames);
00241 }
00242 
00243 /*----------------------------------------------------------------------------*/
00249 /*----------------------------------------------------------------------------*/
00250 static int kmos_dark_destroy(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     cpl_parameterlist_delete(recipe->parameters);
00260     return 0 ;
00261 }
00262 
00263 /*----------------------------------------------------------------------------*/
00273 /*----------------------------------------------------------------------------*/
00274 static int kmos_dark(cpl_parameterlist * parlist, cpl_frameset * frameset)
00275 {
00276     const cpl_parameter *   par ;
00277     int                     nx, ny, nz, ne, ndit ;
00278     const char          *   cmethod ;
00279     const char          *   my_method ;
00280     cpl_frame           *   frame ;
00281     int                     file_extension, citer, cmin, cmax ;
00282     double                  pos_bad_pix_rej, neg_bad_pix_rej, cneg_rej,
00283                             cpos_rej, exptime, gain, qc_dark, qc_dark_median, 
00284                             qc_readnoise, qc_readnoise_median, qc_bad_pix_num ;
00285     char                *   filename ;
00286     char                *   filename_bad ;
00287     char                *   extname ;
00288     char                *   exptimeStr ;
00289     cpl_imagelist       *   detector_in_window ;
00290     cpl_image           *   img_in_window ;
00291     cpl_image           *   combined_data_window ;
00292     cpl_image           *   combined_data ;
00293     cpl_image           *   combined_noise_window ;
00294     cpl_image           *   combined_noise ;
00295     cpl_image           *   bad_pix_mask_window ;
00296     cpl_image           *   bad_pix_mask ;
00297     cpl_propertylist    *   sub_header ;
00298     int                     i ;
00299     
00300     /* Check entries */
00301     if (parlist == NULL || frameset == NULL) {
00302         cpl_msg_error(__func__, "Null Inputs") ;
00303         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00304         return -1 ;
00305     }
00306 
00307     /* Get Parameters */
00308     par=cpl_parameterlist_find_const(parlist, "kmos.kmos_dark.pos_bad_pix_rej");
00309     pos_bad_pix_rej = cpl_parameter_get_double(par);
00310     par=cpl_parameterlist_find_const(parlist, "kmos.kmos_dark.neg_bad_pix_rej");
00311     neg_bad_pix_rej = cpl_parameter_get_double(par);
00312     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_dark.file_extension");
00313     file_extension = cpl_parameter_get_bool(par);
00314     kmos_combine_pars_load(parlist, "kmos.kmos_dark", &cmethod, &cpos_rej,
00315        &cneg_rej, &citer, &cmin, &cmax, FALSE);
00316 
00317     /* Identify the RAW and CALIB frames in the input frameset */
00318     if (kmo_dfs_set_groups(frameset, "kmos_dark") != 1) {
00319         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00320         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00321         return -1 ;
00322     }
00323 
00324     /* Check the inputs consistency */
00325     if (kmos_dark_check_inputs(frameset, &nx, &ny, &ndit, &ne, &exptime) != 1) {
00326         cpl_msg_error(__func__, "Input frameset is not consistent") ;
00327         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00328         return -1 ;
00329     }
00330 
00331     /* Use average method in case there is only 1 input */
00332     my_method = cmethod;
00333     if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00334         cpl_msg_warning(cpl_func, 
00335                 "cmethod is set to 'average' since there is only 1 input");
00336         my_method = "average";
00337     }
00338 
00339     /* Compute output file names */
00340     if (file_extension) {
00341         /* Delete trailing zeros  */
00342         /* If zero right after decimal point,delete point as well */
00343         exptimeStr = cpl_sprintf("%g", exptime);
00344         char *p = 0;
00345         for(p=exptimeStr; *p; ++p) {
00346             if('.' == *p) {
00347                 while(*++p);
00348                 while('0'==*--p) *p = '\0';
00349                 if(*p == '.') *p = '\0';
00350                 break;
00351             }
00352         }
00353         filename = cpl_sprintf("%s_%s", MASTER_DARK, exptimeStr);
00354         filename_bad = cpl_sprintf("%s_%s", BADPIXEL_DARK, exptimeStr);
00355         cpl_free(exptimeStr);
00356     } else {
00357         filename = cpl_sprintf("%s", MASTER_DARK);
00358         filename_bad = cpl_sprintf("%s", BADPIXEL_DARK);
00359     }
00360 
00361     /* Create primary header products */
00362     frame = kmo_dfs_get_frame(frameset, DARK);
00363     kmo_dfs_save_main_header(frameset, filename, "", frame, NULL, parlist, 
00364             cpl_func);
00365     kmo_dfs_save_main_header(frameset, filename_bad, "", frame, NULL, parlist, 
00366             cpl_func);
00367 
00368     /* Loop on detectors */
00369     for (i = 1; i <= ne ; i++) {
00370         cpl_msg_info(cpl_func, "Processing detector No. %d", i);
00371         cpl_msg_indent_more() ;
00372 
00373         detector_in_window = cpl_imagelist_new();
00374         frame = kmo_dfs_get_frame(frameset, DARK);
00375         nz = 0;
00376         while (frame != NULL) {
00377             /* Load current detector DARK frames into an imagelist */
00378             img_in_window = cpl_image_load_window(cpl_frame_get_filename(frame),
00379                     CPL_TYPE_FLOAT, 0, i, KMOS_BADPIX_BORDER+1,
00380                     KMOS_BADPIX_BORDER+1, nx-KMOS_BADPIX_BORDER,
00381                     ny-KMOS_BADPIX_BORDER) ;
00382             if (img_in_window == NULL) {
00383                 cpl_free(filename) ;
00384                 cpl_free(filename_bad) ;
00385                 cpl_imagelist_delete(detector_in_window) ;
00386                 cpl_msg_error(__func__, "Cannot load frame %d", nz+1) ;
00387                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00388                 cpl_msg_indent_less() ;
00389                 return -1 ;
00390             }
00391             cpl_imagelist_set(detector_in_window, img_in_window, nz);
00392             nz++;
00393                     
00394             /* Get next DARK frame */
00395             frame = kmo_dfs_get_frame(frameset, NULL);
00396         }
00397 
00398         /* Combine imagelist and create noise */
00399         kmos_combine_frames(detector_in_window, my_method, 
00400                 cpos_rej, cneg_rej, citer, cmax, cmin, &combined_data_window, 
00401                 &combined_noise_window, -1.0);
00402         cpl_imagelist_delete(detector_in_window) ;
00403 
00404         if (kmclipm_omit_warning_one_slice > 10) 
00405             kmclipm_omit_warning_one_slice = FALSE;
00406     
00407         /* Calculate preliminary mean and stdev to create the BPM */
00408         qc_dark = cpl_image_get_mean(combined_data_window);
00409 
00410         /* Check the noise frame (NULL or ALL pixels are bad) */
00411         if (combined_noise_window == NULL ||
00412                 cpl_image_count_rejected(combined_noise_window) ==
00413                 cpl_image_get_size_x(combined_noise_window)*
00414                 cpl_image_get_size_y(combined_noise_window)) {
00415             qc_readnoise = cpl_image_get_stdev(combined_data_window);
00416         } else {
00417             if (nz > 2)         
00418                 qc_readnoise = cpl_image_get_mean(combined_noise_window);
00419             else if (nz == 2)  
00420                 qc_readnoise = cpl_image_get_stdev(combined_noise_window);
00421             else if (nz == 1)
00422                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00423             else {
00424                 cpl_msg_error(__func__, "Not enough frames: %d", nz) ;
00425                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00426                 cpl_free(filename) ;
00427                 cpl_free(filename_bad) ;
00428                 cpl_image_delete(combined_data_window);
00429                 cpl_image_delete(combined_noise_window);
00430                 cpl_msg_indent_less() ;
00431                 return -1 ;
00432             }
00433         }
00434 
00435         /* Create bad-pixel-mask */
00436         qc_bad_pix_num = kmo_create_bad_pix_dark(combined_data_window, 
00437                 qc_dark, qc_readnoise, pos_bad_pix_rej, neg_bad_pix_rej, 
00438                 &bad_pix_mask_window);
00439 
00440         sub_header = kmo_dfs_load_sub_header(frameset, DARK, i, FALSE);
00441         kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, qc_bad_pix_num, 
00442                 "[] nr. of bad pixels");
00443 
00444         /* Calculate QC.DARK, QC.READNOISE, QC.DARK.MEDIAN, */
00445         /* QC.READNOISE.MEDIAN, QC.DARKCUR */
00446 
00447         /* Badpixels from combined_data_window are already rejected */
00448         /* by kmo_create_bad_pix_dark() */
00449         kmo_image_reject_from_mask(combined_noise_window, bad_pix_mask_window);
00450         qc_dark = cpl_image_get_mean(combined_data_window);
00451         qc_dark_median = cpl_image_get_median(combined_data_window);
00452 
00453         /* Check the noise frame (NULL or ALL pixels are bad) */
00454         /* Calculate mean and stddev of combined frames (with rejection) */
00455         if (combined_noise_window == NULL ||
00456                 cpl_image_count_rejected(combined_noise_window) ==
00457                 cpl_image_get_size_x(combined_noise_window)*
00458                 cpl_image_get_size_y(combined_noise_window)) {
00459             qc_readnoise = cpl_image_get_stdev(combined_data_window);
00460             qc_readnoise_median = 
00461                 kmo_image_get_stdev_median(combined_data_window);
00462         } else {
00463             if (nz > 2) {         
00464                 qc_readnoise = 
00465                     cpl_image_get_mean(combined_noise_window) * sqrt(nz) ;
00466                 qc_readnoise_median =
00467                     cpl_image_get_median(combined_noise_window) * sqrt(nz);
00468             } else if (nz == 2) {   
00469                 qc_readnoise = 
00470                     cpl_image_get_stdev(combined_noise_window) * sqrt(nz) ;
00471                 qc_readnoise_median = sqrt(nz) *
00472                     kmo_image_get_stdev_median(combined_noise_window) ;
00473             } else if (nz == 1) {
00474                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00475                 qc_readnoise_median =
00476                     kmo_image_get_stdev_median(combined_data_window);
00477             } else {
00478                 cpl_msg_error(__func__, "Not enough frames: %d", nz) ;
00479                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00480                 cpl_free(filename) ;
00481                 cpl_free(filename_bad) ;
00482                 cpl_image_delete(combined_data_window);
00483                 cpl_image_delete(combined_noise_window);
00484                 cpl_image_delete(bad_pix_mask_window);
00485                 cpl_propertylist_delete(sub_header);
00486                 cpl_msg_indent_less() ;
00487                 return -1 ;
00488             }
00489         }
00490 
00491         kmclipm_update_property_double(sub_header, QC_DARK, qc_dark, 
00492                 "[adu] mean of master dark");
00493         kmclipm_update_property_double(sub_header, QC_READNOISE, qc_readnoise, 
00494                 "[adu] mean noise of master dark");
00495         kmclipm_update_property_double(sub_header, QC_DARK_MEDIAN, 
00496                 qc_dark_median, "[adu] median of master dark");
00497         kmclipm_update_property_double(sub_header, QC_READNOISE_MEDIAN, 
00498                 qc_readnoise_median, "[adu] median noise of master dark");
00499 
00500         /* Load gain */
00501         gain = kmo_dfs_get_property_double(sub_header, GAIN);
00502         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00503             cpl_msg_error(__func__, "GAIN is missing in header") ;
00504             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00505             cpl_free(filename) ;
00506             cpl_free(filename_bad) ;
00507             cpl_image_delete(combined_data_window);
00508             cpl_image_delete(combined_noise_window);
00509             cpl_image_delete(bad_pix_mask_window);
00510             cpl_propertylist_delete(sub_header);
00511             cpl_msg_indent_less() ;
00512             return -1 ;
00513         }
00514 
00515         kmclipm_update_property_double(sub_header, QC_DARK_CURRENT, 
00516                 qc_dark / exptime / gain, "[e-/s] dark current");
00517 
00518         /* Save dark frame */
00519         extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
00520         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00521                 "FITS extension name");
00522         cpl_free(extname);
00523 
00524         combined_data = kmo_add_bad_pix_border(combined_data_window, TRUE);
00525         cpl_image_delete(combined_data_window);
00526 
00527         kmo_dfs_save_image(combined_data, filename, "", sub_header, 0./0.);
00528         cpl_image_delete(combined_data);
00529 
00530         /* Save noise frame */
00531         extname = kmo_extname_creator(detector_frame, i, EXT_NOISE);
00532         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00533                 "FITS extension name");
00534         cpl_free(extname);
00535 
00536         combined_noise = kmo_add_bad_pix_border(combined_noise_window, TRUE);
00537         cpl_image_delete(combined_noise_window);
00538 
00539         kmo_dfs_save_image(combined_noise, filename, "", sub_header, 0./0.);
00540         cpl_image_delete(combined_noise);
00541 
00542         /* Save bad_pix frame */
00543         extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX);
00544         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00545                 "FITS extension name");
00546         cpl_free(extname);
00547 
00548         bad_pix_mask = kmo_add_bad_pix_border(bad_pix_mask_window, FALSE);
00549         cpl_image_delete(bad_pix_mask_window);
00550 
00551         kmo_dfs_save_image(bad_pix_mask, filename_bad, "", sub_header, 0.);
00552         cpl_image_delete(bad_pix_mask);
00553         
00554         cpl_propertylist_delete(sub_header);
00555 
00556         cpl_msg_indent_less() ;
00557     } 
00558 
00559     /* Free and Return */
00560     cpl_free(filename);
00561     cpl_free(filename_bad);
00562     return CPL_ERROR_NONE;
00563 }
00564 
00567 /*----------------------------------------------------------------------------*/
00578 /*----------------------------------------------------------------------------*/
00579 static int kmos_dark_check_inputs(
00580         cpl_frameset        *   frameset,
00581         int                 *   nx,
00582         int                 *   ny,
00583         int                 *   ndit,
00584         int                 *   ne,
00585         double              *   exptime)
00586 {
00587     cpl_frame           *   frame ;
00588     cpl_propertylist    *   eh ;
00589     cpl_propertylist    *   main_header ;
00590     int                     nx_cur, ny_cur, ndit_cur, ne_cur ;
00591     double                  exptime_cur ;
00592     int                     i, j ;
00593 
00594     /* Check Entries */
00595     if (nx == NULL || ny == NULL || frameset == NULL || exptime == NULL ||
00596             ndit == NULL || ne == NULL) {
00597         return -1;
00598     }
00599 
00600     /* More than 3 frames is recommended */
00601     if (cpl_frameset_count_tags(frameset, DARK) < 3) {
00602         cpl_msg_warning(cpl_func, "3 DARK frames or more are recommended");
00603     }
00604 
00605     /* Loop on the frames - Check Main Headers consistency */
00606     i = 0;
00607     frame = kmo_dfs_get_frame(frameset, DARK);
00608     while (frame != NULL) {
00609         /* Get Frame nb of extensions */
00610         ne_cur = cpl_frame_get_nextensions(frame);
00611 
00612         /* Read Frame header */
00613         main_header = cpl_propertylist_load(cpl_frame_get_filename(frame),0);
00614         ndit_cur = kmos_pfits_get_ndit(main_header) ;
00615         exptime_cur = kmos_pfits_get_exptime(main_header) ;
00616         cpl_propertylist_delete(main_header) ;
00617 
00618         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00619             cpl_msg_error(__func__, "Cannot retrieve keywords from header") ;
00620             return -1 ;
00621         }
00622 
00623         if (i == 0) {
00624             *exptime = exptime_cur ;
00625             *ndit = ndit_cur ;
00626             *ne = ne_cur ;
00627         } else {
00628             if (ndit_cur != *ndit || ne_cur != *ne || 
00629                     fabs(exptime_cur-(*exptime)) >1e-3) {
00630                 cpl_msg_error(__func__, "Header keywords are inconsistent") ;
00631                 return -1 ;
00632             }
00633         }
00634 
00635         /* Get next DARK frame */
00636         frame = kmo_dfs_get_frame(frameset, NULL);
00637         i++;
00638     }
00639 
00640     /* Loop on the frames - Check Extension Headers consistency */
00641     i = 0;
00642     frame = kmo_dfs_get_frame(frameset, DARK);
00643     while (frame != NULL) {
00644         /* Loop on extensions */
00645         for (j=1 ; j<=*ne ; j++) {
00646             /* Read extension header */
00647             eh = cpl_propertylist_load(cpl_frame_get_filename(frame), j);
00648             nx_cur = kmos_pfits_get_naxis1(eh) ;
00649             ny_cur = kmos_pfits_get_naxis2(eh) ;
00650             cpl_propertylist_delete(eh) ;
00651             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00652                 cpl_msg_error(__func__, "Cannot retrieve keywords from header");
00653                 return -1 ;
00654             }
00655 
00656             if (i == 0 && j == 1) {
00657                 *nx = nx_cur ;
00658                 *ny = ny_cur ;
00659             } else {
00660                 if (nx_cur != *nx || ny_cur != *ny) {
00661                     cpl_msg_error(__func__, "Header keywords are inconsistent");
00662                     return -1 ;
00663                 }
00664             }
00665         }
00666 
00667         /* Get next DARK frame */
00668         frame = kmo_dfs_get_frame(frameset, NULL);
00669         i++;
00670     }
00671 
00672     /* Check Sizeѕ */
00673     if (*nx <= 2*KMOS_BADPIX_BORDER || *ny <= 2*KMOS_BADPIX_BORDER) {
00674         cpl_msg_error(__func__, "Input frames x/y size must be > 9 pixels");
00675         return -1 ;
00676     }
00677 
00678     /* Return */
00679     return 1 ;
00680 }
00681 
00682 
00683