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