KMOS Pipeline Reference Manual  1.3.11
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, next, 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     /* Inistialise */
00308     nx = ny = next = -1 ;
00309     exptime = -1.0 ;
00310 
00311     /* Get Parameters */
00312     par=cpl_parameterlist_find_const(parlist, "kmos.kmos_dark.pos_bad_pix_rej");
00313     pos_bad_pix_rej = cpl_parameter_get_double(par);
00314     par=cpl_parameterlist_find_const(parlist, "kmos.kmos_dark.neg_bad_pix_rej");
00315     neg_bad_pix_rej = cpl_parameter_get_double(par);
00316     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_dark.file_extension");
00317     file_extension = cpl_parameter_get_bool(par);
00318     kmos_combine_pars_load(parlist, "kmos.kmos_dark", &cmethod, &cpos_rej,
00319        &cneg_rej, &citer, &cmin, &cmax, FALSE);
00320 
00321     /* Identify the RAW and CALIB frames in the input frameset */
00322     if (kmo_dfs_set_groups(frameset, "kmos_dark") != 1) {
00323         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00324         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00325         return -1 ;
00326     }
00327 
00328     /* Check the inputs consistency */
00329     if (kmos_dark_check_inputs(frameset, &nx, &ny, &ndit, &next,&exptime) != 1){
00330         cpl_msg_error(__func__, "Input frameset is not consistent") ;
00331         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00332         return -1 ;
00333     }
00334 
00335     /* Use average method in case there is only 1 input */
00336     my_method = cmethod;
00337     if (cpl_frameset_count_tags(frameset, DARK) == 1) {
00338         cpl_msg_warning(cpl_func, 
00339                 "cmethod is set to 'average' since there is only 1 input");
00340         my_method = "average";
00341     }
00342 
00343     /* Compute output file names */
00344     if (file_extension) {
00345         /* Delete trailing zeros  */
00346         /* If zero right after decimal point,delete point as well */
00347         exptimeStr = cpl_sprintf("%g", exptime);
00348         char *p = 0;
00349         for(p=exptimeStr; *p; ++p) {
00350             if('.' == *p) {
00351                 while(*++p);
00352                 while('0'==*--p) *p = '\0';
00353                 if(*p == '.') *p = '\0';
00354                 break;
00355             }
00356         }
00357         filename = cpl_sprintf("%s_%s", MASTER_DARK, exptimeStr);
00358         filename_bad = cpl_sprintf("%s_%s", BADPIXEL_DARK, exptimeStr);
00359         cpl_free(exptimeStr);
00360     } else {
00361         filename = cpl_sprintf("%s", MASTER_DARK);
00362         filename_bad = cpl_sprintf("%s", BADPIXEL_DARK);
00363     }
00364 
00365     /* Create primary header products */
00366     frame = kmo_dfs_get_frame(frameset, DARK);
00367     kmo_dfs_save_main_header(frameset, filename, "", frame, NULL, parlist, 
00368             cpl_func);
00369     kmo_dfs_save_main_header(frameset, filename_bad, "", frame, NULL, parlist, 
00370             cpl_func);
00371 
00372     /* Loop on detectors */
00373     for (i = 1; i <= next ; i++) {
00374         cpl_msg_info(cpl_func, "Processing detector No. %d", i);
00375         cpl_msg_indent_more() ;
00376 
00377         detector_in_window = cpl_imagelist_new();
00378         frame = kmo_dfs_get_frame(frameset, DARK);
00379         nz = 0;
00380         while (frame != NULL) {
00381             /* Load current detector DARK frames into an imagelist */
00382             img_in_window = cpl_image_load_window(cpl_frame_get_filename(frame),
00383                     CPL_TYPE_FLOAT, 0, i, KMOS_BADPIX_BORDER+1,
00384                     KMOS_BADPIX_BORDER+1, nx-KMOS_BADPIX_BORDER,
00385                     ny-KMOS_BADPIX_BORDER) ;
00386             if (img_in_window == NULL) {
00387                 cpl_free(filename) ;
00388                 cpl_free(filename_bad) ;
00389                 cpl_imagelist_delete(detector_in_window) ;
00390                 cpl_msg_error(__func__, "Cannot load frame %d", nz+1) ;
00391                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00392                 cpl_msg_indent_less() ;
00393                 return -1 ;
00394             }
00395             cpl_imagelist_set(detector_in_window, img_in_window, nz);
00396             nz++;
00397                     
00398             /* Get next DARK frame */
00399             frame = kmo_dfs_get_frame(frameset, NULL);
00400         }
00401 
00402         /* Combine imagelist and create noise */
00403         kmos_combine_frames(detector_in_window, my_method, 
00404                 cpos_rej, cneg_rej, citer, cmax, cmin, &combined_data_window, 
00405                 &combined_noise_window, -1.0);
00406         cpl_imagelist_delete(detector_in_window) ;
00407 
00408         if (kmclipm_omit_warning_one_slice > 10) 
00409             kmclipm_omit_warning_one_slice = FALSE;
00410     
00411         /* Calculate preliminary mean and stdev to create the BPM */
00412         qc_dark = cpl_image_get_mean(combined_data_window);
00413 
00414         /* Check the noise frame (NULL or ALL pixels are bad) */
00415         if (combined_noise_window == NULL ||
00416                 cpl_image_count_rejected(combined_noise_window) ==
00417                 cpl_image_get_size_x(combined_noise_window)*
00418                 cpl_image_get_size_y(combined_noise_window)) {
00419             qc_readnoise = cpl_image_get_stdev(combined_data_window);
00420         } else {
00421             if (nz > 2)         
00422                 qc_readnoise = cpl_image_get_mean(combined_noise_window);
00423             else if (nz == 2)  
00424                 qc_readnoise = cpl_image_get_stdev(combined_noise_window);
00425             else if (nz == 1)
00426                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00427             else {
00428                 cpl_msg_error(__func__, "Not enough frames: %d", nz) ;
00429                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00430                 cpl_free(filename) ;
00431                 cpl_free(filename_bad) ;
00432                 cpl_image_delete(combined_data_window);
00433                 cpl_image_delete(combined_noise_window);
00434                 cpl_msg_indent_less() ;
00435                 return -1 ;
00436             }
00437         }
00438 
00439         /* Create bad-pixel-mask */
00440         qc_bad_pix_num = kmo_create_bad_pix_dark(combined_data_window, 
00441                 qc_dark, qc_readnoise, pos_bad_pix_rej, neg_bad_pix_rej, 
00442                 &bad_pix_mask_window);
00443 
00444         sub_header = kmo_dfs_load_sub_header(frameset, DARK, i, FALSE);
00445         kmclipm_update_property_int(sub_header, QC_NR_BAD_PIX, qc_bad_pix_num, 
00446                 "[] nr. of bad pixels");
00447 
00448         /* Calculate QC.DARK, QC.READNOISE, QC.DARK.MEDIAN, */
00449         /* QC.READNOISE.MEDIAN, QC.DARKCUR */
00450 
00451         /* Badpixels from combined_data_window are already rejected */
00452         /* by kmo_create_bad_pix_dark() */
00453         kmo_image_reject_from_mask(combined_noise_window, bad_pix_mask_window);
00454         qc_dark = cpl_image_get_mean(combined_data_window);
00455         qc_dark_median = cpl_image_get_median(combined_data_window);
00456 
00457         /* Check the noise frame (NULL or ALL pixels are bad) */
00458         /* Calculate mean and stddev of combined frames (with rejection) */
00459         if (combined_noise_window == NULL ||
00460                 cpl_image_count_rejected(combined_noise_window) ==
00461                 cpl_image_get_size_x(combined_noise_window)*
00462                 cpl_image_get_size_y(combined_noise_window)) {
00463             qc_readnoise = cpl_image_get_stdev(combined_data_window);
00464             qc_readnoise_median = 
00465                 kmo_image_get_stdev_median(combined_data_window);
00466         } else {
00467             if (nz > 2) {         
00468                 qc_readnoise = 
00469                     cpl_image_get_mean(combined_noise_window) * sqrt(nz) ;
00470                 qc_readnoise_median =
00471                     cpl_image_get_median(combined_noise_window) * sqrt(nz);
00472             } else if (nz == 2) {   
00473                 qc_readnoise = 
00474                     cpl_image_get_stdev(combined_noise_window) * sqrt(nz) ;
00475                 qc_readnoise_median = sqrt(nz) *
00476                     kmo_image_get_stdev_median(combined_noise_window) ;
00477             } else if (nz == 1) {
00478                 qc_readnoise = cpl_image_get_stdev(combined_data_window);
00479                 qc_readnoise_median =
00480                     kmo_image_get_stdev_median(combined_data_window);
00481             } else {
00482                 cpl_msg_error(__func__, "Not enough frames: %d", nz) ;
00483                 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00484                 cpl_free(filename) ;
00485                 cpl_free(filename_bad) ;
00486                 cpl_image_delete(combined_data_window);
00487                 cpl_image_delete(combined_noise_window);
00488                 cpl_image_delete(bad_pix_mask_window);
00489                 cpl_propertylist_delete(sub_header);
00490                 cpl_msg_indent_less() ;
00491                 return -1 ;
00492             }
00493         }
00494 
00495         kmclipm_update_property_double(sub_header, QC_DARK, qc_dark, 
00496                 "[adu] mean of master dark");
00497         kmclipm_update_property_double(sub_header, QC_READNOISE, qc_readnoise, 
00498                 "[adu] mean noise of master dark");
00499         kmclipm_update_property_double(sub_header, QC_DARK_MEDIAN, 
00500                 qc_dark_median, "[adu] median of master dark");
00501         kmclipm_update_property_double(sub_header, QC_READNOISE_MEDIAN, 
00502                 qc_readnoise_median, "[adu] median noise of master dark");
00503 
00504         /* Load gain */
00505         gain = kmo_dfs_get_property_double(sub_header, GAIN);
00506         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00507             cpl_msg_error(__func__, "GAIN is missing in header") ;
00508             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00509             cpl_free(filename) ;
00510             cpl_free(filename_bad) ;
00511             cpl_image_delete(combined_data_window);
00512             cpl_image_delete(combined_noise_window);
00513             cpl_image_delete(bad_pix_mask_window);
00514             cpl_propertylist_delete(sub_header);
00515             cpl_msg_indent_less() ;
00516             return -1 ;
00517         }
00518 
00519         kmclipm_update_property_double(sub_header, QC_DARK_CURRENT, 
00520                 qc_dark / exptime / gain, "[e-/s] dark current");
00521 
00522         /* Save dark frame */
00523         extname = kmo_extname_creator(detector_frame, i, EXT_DATA);
00524         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00525                 "FITS extension name");
00526         cpl_free(extname);
00527 
00528         combined_data = kmo_add_bad_pix_border(combined_data_window, TRUE);
00529         cpl_image_delete(combined_data_window);
00530 
00531         kmo_dfs_save_image(combined_data, filename, "", sub_header, 0./0.);
00532         cpl_image_delete(combined_data);
00533 
00534         /* Save noise frame */
00535         extname = kmo_extname_creator(detector_frame, i, EXT_NOISE);
00536         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00537                 "FITS extension name");
00538         cpl_free(extname);
00539 
00540         combined_noise = kmo_add_bad_pix_border(combined_noise_window, TRUE);
00541         cpl_image_delete(combined_noise_window);
00542 
00543         kmo_dfs_save_image(combined_noise, filename, "", sub_header, 0./0.);
00544         cpl_image_delete(combined_noise);
00545 
00546         /* Save bad_pix frame */
00547         extname = kmo_extname_creator(detector_frame, i, EXT_BADPIX);
00548         kmclipm_update_property_string(sub_header, EXTNAME, extname, 
00549                 "FITS extension name");
00550         cpl_free(extname);
00551 
00552         bad_pix_mask = kmo_add_bad_pix_border(bad_pix_mask_window, FALSE);
00553         cpl_image_delete(bad_pix_mask_window);
00554 
00555         kmo_dfs_save_image(bad_pix_mask, filename_bad, "", sub_header, 0.);
00556         cpl_image_delete(bad_pix_mask);
00557         
00558         cpl_propertylist_delete(sub_header);
00559 
00560         cpl_msg_indent_less() ;
00561     } 
00562 
00563     /* Free and Return */
00564     cpl_free(filename);
00565     cpl_free(filename_bad);
00566     return CPL_ERROR_NONE;
00567 }
00568 
00571 /*----------------------------------------------------------------------------*/
00582 /*----------------------------------------------------------------------------*/
00583 static int kmos_dark_check_inputs(
00584         cpl_frameset        *   frameset,
00585         int                 *   nx,
00586         int                 *   ny,
00587         int                 *   ndit,
00588         int                 *   next,
00589         double              *   exptime)
00590 {
00591     cpl_frame           *   frame ;
00592     cpl_propertylist    *   eh ;
00593     cpl_propertylist    *   main_header ;
00594     int                     nx_cur, ny_cur, ndit_cur, ne_cur ;
00595     double                  exptime_cur ;
00596     int                     i, j ;
00597 
00598     /* Check Entries */
00599     if (nx == NULL || ny == NULL || frameset == NULL || exptime == NULL ||
00600             ndit == NULL || next == NULL) {
00601         return -1;
00602     }
00603 
00604     /* More than 3 frames is recommended */
00605     if (cpl_frameset_count_tags(frameset, DARK) < 3) {
00606         cpl_msg_warning(cpl_func, "3 DARK frames or more are recommended");
00607     }
00608 
00609     /* Loop on the frames - Check Main Headers consistency */
00610     i = 0;
00611     frame = kmo_dfs_get_frame(frameset, DARK);
00612     while (frame != NULL) {
00613         /* Get Frame nb of extensions */
00614         ne_cur = cpl_frame_get_nextensions(frame);
00615 
00616         /* Read Frame header */
00617         main_header = cpl_propertylist_load(cpl_frame_get_filename(frame),0);
00618         ndit_cur = kmos_pfits_get_ndit(main_header) ;
00619         exptime_cur = kmos_pfits_get_exptime(main_header) ;
00620         cpl_propertylist_delete(main_header) ;
00621 
00622         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00623             cpl_msg_error(__func__, "Cannot retrieve keywords from header") ;
00624             return -1 ;
00625         }
00626 
00627         if (i == 0) {
00628             *exptime = exptime_cur ;
00629             *ndit = ndit_cur ;
00630             *next = ne_cur ;
00631         } else {
00632             if (ndit_cur != *ndit || ne_cur != *next || 
00633                     fabs(exptime_cur-(*exptime)) >1e-3) {
00634                 cpl_msg_error(__func__, "Header keywords are inconsistent") ;
00635                 return -1 ;
00636             }
00637         }
00638 
00639         /* Get next DARK frame */
00640         frame = kmo_dfs_get_frame(frameset, NULL);
00641         i++;
00642     }
00643 
00644     /* Loop on the frames - Check Extension Headers consistency */
00645     i = 0;
00646     frame = kmo_dfs_get_frame(frameset, DARK);
00647     while (frame != NULL) {
00648         /* Loop on extensions */
00649         for (j=1 ; j<=*next ; j++) {
00650             /* Read extension header */
00651             eh = cpl_propertylist_load(cpl_frame_get_filename(frame), j);
00652             nx_cur = kmos_pfits_get_naxis1(eh) ;
00653             ny_cur = kmos_pfits_get_naxis2(eh) ;
00654             cpl_propertylist_delete(eh) ;
00655             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00656                 cpl_msg_error(__func__, "Cannot retrieve keywords from header");
00657                 return -1 ;
00658             }
00659 
00660             if (i == 0 && j == 1) {
00661                 *nx = nx_cur ;
00662                 *ny = ny_cur ;
00663             } else {
00664                 if (nx_cur != *nx || ny_cur != *ny) {
00665                     cpl_msg_error(__func__, "Header keywords are inconsistent");
00666                     return -1 ;
00667                 }
00668             }
00669         }
00670 
00671         /* Get next DARK frame */
00672         frame = kmo_dfs_get_frame(frameset, NULL);
00673         i++;
00674     }
00675 
00676     /* Check Sizeѕ */
00677     if (*nx <= 2*KMOS_BADPIX_BORDER || *ny <= 2*KMOS_BADPIX_BORDER) {
00678         cpl_msg_error(__func__, "Input frames x/y size must be > 9 pixels");
00679         return -1 ;
00680     }
00681 
00682     /* Return */
00683     return 1 ;
00684 }
00685 
00686 
00687