CRIRES Pipeline Reference Manual  2.3.2
crires_spec_flat.c
00001 /* $Id: crires_spec_flat.c,v 1.56 2012-09-19 14:10:27 yjung Exp $
00002  *
00003  * This file is part of the CRIRES Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: yjung $
00023  * $Date: 2012-09-19 14:10:27 $
00024  * $Revision: 1.56 $
00025  * $Name: not supported by cvs2svn $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include "crires_recipe.h"
00037 
00038 #include "crires_combine.h"
00039 
00040 /*-----------------------------------------------------------------------------
00041                                 Define
00042  -----------------------------------------------------------------------------*/
00043 
00044 #define RECIPE_STRING "crires_spec_flat"
00045 
00046 /*-----------------------------------------------------------------------------
00047                             Functions prototypes
00048  -----------------------------------------------------------------------------*/
00049 
00050 static cpl_imagelist * crires_spec_flat_reduce(cpl_frameset *, const char *,
00051         const char *) ;
00052 static cpl_imagelist * crires_spec_flat_bpm(cpl_imagelist *, double, 
00053         double, double) ;
00054 static int crires_spec_flat_save(const cpl_imagelist *, const cpl_imagelist *, 
00055         int, cpl_frameset *, const cpl_parameterlist *, cpl_frameset *) ;
00056 static int crires_spec_flat_compare(const cpl_frame *, const cpl_frame *) ;
00057 
00058 static char crires_spec_flat_description[] =
00059 "crires_spec_flat -- Flat-field recipe\n"
00060 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00061 "raw-file.fits "CRIRES_SPEC_FLAT_RAW" or\n"
00062 "dark-file.fits "CRIRES_CALPRO_DARK" or\n"
00063 "detlin-file.fits "CRIRES_CALPRO_COEFFS_CUBE".\n" ;
00064 
00065 CRIRES_RECIPE_DEFINE(crires_spec_flat,
00066         CRIRES_PARAM_THRESHOLDS     |
00067         CRIRES_PARAM_BPM_RATE       |
00068         CRIRES_PARAM_REPLACE        |
00069         CRIRES_PARAM_CLEAN_FLAT     |
00070         CRIRES_PARAM_NORM_STARTY    |
00071         CRIRES_PARAM_NORM_STOPY     |
00072         CRIRES_PARAM_KAPPA_SIGCLIP  |
00073         CRIRES_PARAM_COLLAPSE_METH,
00074         "Flatfield recipe",
00075         crires_spec_flat_description) ;
00076 
00077 /*-----------------------------------------------------------------------------
00078                             Static variables
00079  -----------------------------------------------------------------------------*/
00080 
00081 static struct {
00082     /* Input */
00083     double                  bpm_low ;
00084     double                  bpm_high ;
00085     double                  bpm_lines_ratio ;
00086     int                     replace_flag ;
00087     int                     clean_flat_flag ;
00088     int                     starty ;
00089     int                     stopy ;
00090     double                  kappa_sigclip ;
00091     crires_collapse_method  coll_meth ;
00092     /* Output */
00093     crires_illum_period     period ;
00094     int                     bpm_nb[CRIRES_NB_DETECTORS] ;
00095     double                  flat_mean[CRIRES_NB_DETECTORS] ;
00096     double                  flat_stdev[CRIRES_NB_DETECTORS] ;
00097     double                  flat_flux[CRIRES_NB_DETECTORS] ;
00098     double                  flat_master_rms[CRIRES_NB_DETECTORS] ;
00099 } crires_spec_flat_config ;
00100 
00101 /*-----------------------------------------------------------------------------
00102                                 Functions code
00103  -----------------------------------------------------------------------------*/
00104 
00105 /*----------------------------------------------------------------------------*/
00112 /*----------------------------------------------------------------------------*/
00113 static int crires_spec_flat(
00114         cpl_frameset            *   frameset,
00115         const cpl_parameterlist *   parlist)
00116 {
00117     const char      *   sval ;
00118     cpl_size        *   labels ;
00119     cpl_size            nlabels ;
00120     cpl_frameset    *   rawframes ;
00121     const char      *   dark ;
00122     const char      *   detlin ;
00123     cpl_imagelist   *   flat ;
00124     cpl_frameset    *   flat_one ;
00125     cpl_imagelist   *   bpm ;
00126     int                 i ;
00127 
00128     /* Initialise */
00129     rawframes = NULL ;
00130     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00131         crires_spec_flat_config.bpm_nb[i] = -1 ;
00132         crires_spec_flat_config.flat_mean[i] = -1.0 ;
00133         crires_spec_flat_config.flat_stdev[i] = -1.0 ;
00134         crires_spec_flat_config.flat_flux[i] = -1.0 ;
00135         crires_spec_flat_config.flat_master_rms[i] = -1.0 ;
00136     }
00137     
00138     /* Retrieve input parameters */
00139     sval = crires_parameterlist_get_string(parlist, RECIPE_STRING, 
00140             CRIRES_PARAM_THRESHOLDS) ;
00141     if (sscanf(sval, "%lg,%lg",
00142                     &crires_spec_flat_config.bpm_low,
00143                     &crires_spec_flat_config.bpm_high)!=2) {
00144         return -1 ;
00145     }
00146     crires_spec_flat_config.replace_flag = crires_parameterlist_get_bool(
00147             parlist, RECIPE_STRING, CRIRES_PARAM_REPLACE) ;
00148     crires_spec_flat_config.clean_flat_flag = crires_parameterlist_get_bool(
00149             parlist, RECIPE_STRING, CRIRES_PARAM_CLEAN_FLAT) ;
00150     crires_spec_flat_config.bpm_lines_ratio = crires_parameterlist_get_double( 
00151             parlist, RECIPE_STRING, CRIRES_PARAM_BPM_RATE) ;
00152     crires_spec_flat_config.starty = crires_parameterlist_get_int(parlist, 
00153             RECIPE_STRING, CRIRES_PARAM_NORM_STARTY) ;
00154     crires_spec_flat_config.stopy = crires_parameterlist_get_int(parlist, 
00155             RECIPE_STRING, CRIRES_PARAM_NORM_STOPY) ;
00156     crires_spec_flat_config.kappa_sigclip = crires_parameterlist_get_double( 
00157             parlist, RECIPE_STRING, CRIRES_PARAM_KAPPA_SIGCLIP) ;
00158     sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
00159             CRIRES_PARAM_COLLAPSE_METH) ;
00160     if (!strcmp(sval, "avg"))
00161         crires_spec_flat_config.coll_meth = CRIRES_COLLAPSE_AVG ;
00162     else if (!strcmp(sval, "med"))
00163         crires_spec_flat_config.coll_meth = CRIRES_COLLAPSE_MED ;
00164     else if (!strcmp(sval, "sig"))
00165         crires_spec_flat_config.coll_meth = CRIRES_COLLAPSE_SIG ;
00166     else {
00167         cpl_msg_error(__func__, "Invalid collapse method specified");
00168         return -1;
00169     }
00170  
00171     /* Identify the RAW and CALIB frames in the input frameset */
00172     if (crires_dfs_set_groups(frameset, "crires_spec_flat")) {
00173         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00174         return -1 ;
00175     }
00176 
00177     /* Retrieve calibration data */
00178     dark        = crires_extract_filename(frameset, CRIRES_CALPRO_DARK) ;
00179     detlin      = crires_extract_filename(frameset, CRIRES_CALPRO_COEFFS_CUBE) ;
00180 
00181     /* Retrieve raw frames */
00182     if ((rawframes = crires_extract_frameset(frameset, 
00183                     CRIRES_SPEC_FLAT_RAW)) == NULL) {
00184         cpl_msg_error(__func__, "No raw frame in input") ;
00185         return -1 ;
00186     }
00187 
00188     /* Get the detector illumination period */
00189     crires_spec_flat_config.period =
00190         crires_get_detector_illum_period(
00191             cpl_frame_get_filename(cpl_frameset_get_position(rawframes, 0))) ;
00192     if (crires_spec_flat_config.period == CRIRES_ILLUM_UNKNOWN) {
00193         cpl_msg_error(__func__,
00194                 "Cannot determine the detector illumination period") ;
00195         cpl_frameset_delete(rawframes) ;
00196         return -1 ;
00197     } else {
00198         crires_display_detector_illum(crires_spec_flat_config.period) ;
00199     }
00200 
00201     /* Labelise all input frames */
00202     if ((labels = cpl_frameset_labelise(rawframes, crires_spec_flat_compare,
00203                 &nlabels)) == NULL) {
00204         cpl_msg_error(__func__, "Cannot labelise input frames") ;
00205         cpl_frameset_delete(rawframes) ;
00206         return -1 ;
00207     }
00208 
00209     /* Extract settings and reduce each of them */
00210     for (i=0 ; i<(int)nlabels ; i++) {
00211         /* Reduce data set nb i */
00212         cpl_msg_info(__func__, "Reduce data set %d / %"CPL_SIZE_FORMAT, 
00213                 i+1, nlabels);
00214         cpl_msg_indent_more() ;
00215         flat_one = cpl_frameset_extract(rawframes, labels, (cpl_size)i) ;
00216         flat = crires_spec_flat_reduce(flat_one, dark, detlin) ;
00217         cpl_msg_indent_less() ;
00218 
00219         /* Save the products */
00220         cpl_msg_info(__func__, "Save the products") ;
00221         cpl_msg_indent_more() ;
00222         if (flat == NULL) {
00223             cpl_msg_warning(__func__, "Cannot reduce set nb %d", i+1) ;
00224         } else {
00225             if ((bpm = crires_spec_flat_bpm(flat,
00226                             crires_spec_flat_config.bpm_low,
00227                             crires_spec_flat_config.bpm_high,
00228                             crires_spec_flat_config.bpm_lines_ratio)) == NULL) {
00229                 cpl_msg_warning(__func__, "Cannot create bad pixels map") ;
00230             }
00231             crires_spec_flat_save(flat, bpm, i+1, flat_one, parlist, frameset) ;
00232             cpl_imagelist_delete(flat) ;
00233             cpl_imagelist_delete(bpm) ;
00234         }
00235         cpl_msg_indent_less() ;
00236         cpl_frameset_delete(flat_one) ;
00237     }
00238     cpl_frameset_delete(rawframes) ;
00239     cpl_free(labels) ;
00240 
00241     /* Return */
00242     if (cpl_error_get_code()) return -1 ;
00243     else return 0 ;
00244 }
00245 
00246 /*----------------------------------------------------------------------------*/
00254 /*----------------------------------------------------------------------------*/
00255 static cpl_imagelist * crires_spec_flat_reduce(
00256         cpl_frameset    *   flatframes,
00257         const char      *   dark,
00258         const char      *   detlin)
00259 {
00260     cpl_propertylist    *   plist ;
00261     cpl_frame           *   ref_frame ;
00262     const char          *   fname ;
00263     int                     nframes ;
00264     double                  dit_frame, dit_dark ;
00265     cpl_imagelist       *   in ;
00266     cpl_imagelist       *   out ;
00267     cpl_vector          *   medians ;
00268     double                  median ;
00269     cpl_image           *   ima ;
00270     int                     nx, ny, starty, stopy, ly ;
00271     int                     i, j ;
00272 
00273     /* Test entries */
00274     if (flatframes == NULL) return NULL ;
00275 
00276     /* Initialize */
00277     nframes = cpl_frameset_get_size(flatframes) ;
00278     ly = -1 ;
00279 
00280     /* Get the DIT from the RAW frame */
00281     ref_frame = cpl_frameset_get_position(flatframes, 0) ;
00282     fname = cpl_frame_get_filename(ref_frame) ;
00283     if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
00284                     0)) == NULL) {
00285         cpl_msg_error(__func__, "Getting header from RAW file");
00286         cpl_msg_indent_less() ;
00287         return NULL ;
00288     }
00289     dit_frame = crires_pfits_get_dit(plist) ;
00290     cpl_propertylist_delete(plist) ;
00291     if (cpl_error_get_code()) {
00292         cpl_msg_error(__func__, "Cannot get the DIT from RAW file") ;
00293         cpl_msg_indent_less() ;
00294         return NULL ;
00295     }
00296     cpl_msg_info(__func__, "DIT value: %g sec.", dit_frame) ;
00297     
00298     /* Verify the DIT of the dark */
00299     if (dark != NULL) {
00300         cpl_msg_info(__func__, "Verify the dark DIT") ;
00301         cpl_msg_indent_more() ;
00302         if ((plist=cpl_propertylist_load(dark, 0)) == NULL) {
00303             cpl_msg_error(__func__, "Getting header from DARK");
00304             cpl_msg_indent_less() ;
00305             return NULL ;
00306         }
00307         dit_dark = crires_pfits_get_dit(plist) ;
00308         cpl_propertylist_delete(plist) ;
00309         if (cpl_error_get_code()) {
00310             cpl_msg_error(__func__, "Cannot get the DIT from DARK") ;
00311             cpl_msg_indent_less() ;
00312             return NULL ;
00313         }
00314         if (fabs(dit_dark-dit_frame) > 1e-5) {
00315             cpl_msg_error(__func__, "Mismatch RAW DIT (%g) / DARK DIT (%g)",
00316                     dit_frame, dit_dark) ;
00317             cpl_msg_indent_less() ;
00318             return NULL ;
00319         }
00320         cpl_msg_indent_less() ;
00321     }
00322 
00323     /* Create the image list */
00324     out = cpl_imagelist_new() ;
00325     
00326     /* Loop on the detectors */
00327     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00328         cpl_msg_info(__func__, "Compute the MASTER FLAT for chip nb %d", i+1) ;
00329         cpl_msg_indent_more() ;
00330 
00331         /* Load the data */
00332         in = crires_load_frameset(flatframes, crires_spec_flat_config.period, 
00333                 i+1, CPL_TYPE_FLOAT) ;
00334         nx = cpl_image_get_size_x(cpl_imagelist_get(in, 0)) ;
00335         ny = cpl_image_get_size_y(cpl_imagelist_get(in, 0)) ;
00336 
00337         /* Correct for dark and non-linearity */
00338         if (crires_calib_chip_list(in, crires_spec_flat_config.period, i+1, 
00339                     NULL, dark, NULL, detlin, dit_frame, -1, -1, -1)) {
00340             cpl_msg_error(__func__, "Cannot apply the calibrations") ;
00341             cpl_imagelist_delete(in) ;
00342             return NULL ;
00343         }
00344 
00345         /* Create medians vector */
00346         medians = cpl_vector_new(nframes) ;
00347 
00348         /* Handle Vignetting */
00349         if (i+1 == 1) 
00350             ly = crires_get_detector_ly1(crires_spec_flat_config.period) ;
00351         if (i+1 == 2) 
00352             ly = crires_get_detector_ly2(crires_spec_flat_config.period) ;
00353         if (i+1 == 3) 
00354             ly = crires_get_detector_ly3(crires_spec_flat_config.period) ;
00355         if (i+1 == 4) 
00356             ly = crires_get_detector_ly4(crires_spec_flat_config.period) ;
00357         /* If ly not found, use the bottom of the image */
00358         if (ly < 0) ly = 1 ;
00359 
00360         starty = crires_spec_flat_config.starty ;
00361         if (starty < 0) {
00362             starty = 1 ;
00363         } else {
00364             starty -= (ly - 1) ;
00365         }
00366         stopy = crires_spec_flat_config.stopy ;
00367         if (stopy < 0) {
00368             stopy = ny ;
00369         } else {
00370             stopy -= (ly - 1) ;
00371         }
00372 
00373         /* Loop on all the frames */
00374         cpl_msg_info(__func__, "Normalise with the median") ;
00375         for (j=0 ; j<nframes ; j++) {
00376             median = cpl_image_get_median_window(cpl_imagelist_get(in, j), 
00377                     1, starty, nx, stopy) ;
00378             if (cpl_error_get_code()) {
00379                 cpl_msg_error(__func__, "Invalid bounds Y : %d-%d", ly,
00380                         ly+ny-1) ;
00381                 cpl_imagelist_delete(in) ;
00382                 cpl_vector_delete(medians) ;
00383                 return NULL ;
00384             }
00385             cpl_vector_set(medians, j, median) ;
00386             cpl_image_divide_scalar(cpl_imagelist_get(in, j), median) ;
00387         }
00388 
00389         /* Fill QCs */
00390         crires_spec_flat_config.flat_mean[i] = cpl_vector_get_mean(medians) ;
00391         if (cpl_vector_get_size(medians) > 1) 
00392             crires_spec_flat_config.flat_stdev[i]=cpl_vector_get_stdev(medians);
00393         else
00394             crires_spec_flat_config.flat_stdev[i] = -1.0 ;
00395         crires_spec_flat_config.flat_flux[i] =
00396             crires_spec_flat_config.flat_mean[i] / dit_frame ;
00397        
00398         /* Collapse the frames */
00399         if ((ima = crires_combine_collapse_imagelist(in, medians, 
00400                         crires_spec_flat_config.kappa_sigclip,
00401                         i+1,
00402                         crires_spec_flat_config.coll_meth)) == NULL) {
00403             cpl_msg_error(__func__, "Cannot average the flats") ;
00404             cpl_imagelist_delete(in) ;
00405             cpl_vector_delete(medians) ;
00406             return NULL ;
00407         }
00408         cpl_vector_delete(medians) ;
00409         cpl_imagelist_delete(in) ;
00410 
00411         /* Add QC */
00412         crires_spec_flat_config.flat_master_rms[i] =
00413             cpl_image_get_stdev(ima) ;
00414         
00415         /* Set the image in the list */
00416         cpl_imagelist_set(out, ima, i) ;
00417         cpl_msg_indent_less() ;
00418     }
00419 
00420     return out ;
00421 }
00422 
00423 /*----------------------------------------------------------------------------*/
00432 /*----------------------------------------------------------------------------*/
00433 static cpl_imagelist * crires_spec_flat_bpm(
00434         cpl_imagelist       *   flat,
00435         double                  low,
00436         double                  high,
00437         double                  bad_per_line_limit)
00438 {
00439     cpl_imagelist   *   bpm ;
00440     int                 nima ;
00441     cpl_image       *   bpm_cur ;
00442     cpl_mask        *   mask_cur ;
00443     cpl_binary      *   pmask_cur ;
00444     int                 nx, ny, cur_bp_nb ;
00445     int                 i, j, k ;
00446 
00447     /* Test entries */
00448     if (flat == NULL) return NULL ;
00449 
00450     /* Initialise */
00451     nima = cpl_imagelist_get_size(flat) ;
00452 
00453     /* Create the output image list */
00454     bpm = cpl_imagelist_new() ;
00455 
00456     /* Loop on the images */
00457     for (i=0 ; i<nima ; i++) {
00458         /* Threshold to get the BPMs */
00459         if ((mask_cur = cpl_mask_threshold_image_create(
00460                         cpl_imagelist_get(flat, i), low, high)) == NULL) {
00461             cpl_msg_error(__func__, "Cannot create bad pixels map") ;
00462             cpl_imagelist_delete(bpm) ;
00463             return NULL ;
00464         }
00465         cpl_mask_not(mask_cur) ;
00466 
00467         /*
00468         Post processing : Big zones of bad pixels are not considered as
00469         bad pixels. Each line containing more than
00470         100*bad_per_line_limit percent bad pixels is reset to contain
00471         anly good pixels.
00472         */
00473         nx = cpl_mask_get_size_x(mask_cur) ;
00474         ny = cpl_mask_get_size_y(mask_cur) ;
00475         pmask_cur = cpl_mask_get_data(mask_cur) ;
00476         for (j=0 ; j<ny ; j++) {
00477             cur_bp_nb = cpl_mask_count_window(mask_cur, 1, j+1, nx, j+1) ;
00478             /* Check if the line has too many bad pixels */
00479             if (cur_bp_nb > bad_per_line_limit * nx) {
00480                 /* Reset the bad pixels on the current line */
00481                 for (k=0 ; k<nx ; k++) {
00482                     pmask_cur[k+j*nx] = CPL_BINARY_0 ;
00483                 }
00484             }
00485         }
00486 
00487         /* Convert mask to image */
00488         bpm_cur = cpl_image_new_from_mask(mask_cur) ;
00489         crires_spec_flat_config.bpm_nb[i] = cpl_mask_count(mask_cur) ;
00490         cpl_imagelist_set(bpm, bpm_cur, i) ;
00491 
00492         /* Clean the flat using the computed BPM */
00493         if (crires_spec_flat_config.clean_flat_flag) {
00494             cpl_image_reject_from_mask(cpl_imagelist_get(flat, i), mask_cur) ;
00495             cpl_detector_interpolate_rejected(cpl_imagelist_get(flat, i)) ;
00496         }
00497         cpl_mask_delete(mask_cur) ;
00498 
00499         /* Set the flat to 1 outside of the bounds */
00500         if (crires_spec_flat_config.replace_flag) {
00501             cpl_image_threshold(cpl_imagelist_get(flat, i),
00502                     low, high, 1.0, 1.0) ;
00503         }
00504     }
00505     return bpm ;
00506 }
00507 
00508 /*----------------------------------------------------------------------------*/
00518 /*----------------------------------------------------------------------------*/
00519 static int crires_spec_flat_save(
00520         const cpl_imagelist     *   flat,
00521         const cpl_imagelist     *   bpm,
00522         int                         set_nb,
00523         cpl_frameset            *   set,
00524         const cpl_parameterlist *   parlist,
00525         cpl_frameset            *   set_tot)
00526 {
00527     cpl_propertylist    **  qclists ;
00528     const cpl_frame     *   ref_frame ;
00529     char                *   filename ;
00530     cpl_propertylist    *   inputlist ;
00531     const char          *   recipe_name = "crires_spec_flat" ;
00532     int                     i ;
00533 
00534     /* Get the reference frame */
00535     ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
00536 
00537     /* Create the QC lists */
00538     qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00539     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00540         qclists[i] = cpl_propertylist_new() ;
00541         cpl_propertylist_append_int(qclists[i], "ESO QC NBBAD",
00542                 crires_spec_flat_config.bpm_nb[i]) ;
00543         cpl_propertylist_append_double(qclists[i], "ESO QC FLAT MEAN",
00544                 crires_spec_flat_config.flat_mean[i]) ;
00545         cpl_propertylist_append_double(qclists[i], "ESO QC FLAT STDEV",
00546                 crires_spec_flat_config.flat_stdev[i]) ;
00547         cpl_propertylist_append_double(qclists[i], "ESO QC FLAT FLUX",
00548                 crires_spec_flat_config.flat_flux[i]) ;
00549         cpl_propertylist_append_double(qclists[i], "ESO QC FLAT MASTER RMS",
00550                 crires_spec_flat_config.flat_master_rms[i]) ;
00551 
00552         /* Propagate some keywords from input raw frame extensions */
00553         inputlist = cpl_propertylist_load_regexp(
00554                 cpl_frame_get_filename(ref_frame), i+1,
00555                 CRIRES_HEADER_EXT_FORWARD, 0) ;
00556         cpl_propertylist_copy_property_regexp(qclists[i], inputlist, 
00557                 CRIRES_HEADER_EXT_FORWARD, 0) ;
00558         cpl_propertylist_delete(inputlist) ;
00559     }
00560 
00561     /* Write the flat image */
00562     filename = cpl_sprintf("%s_set%02d.fits", recipe_name, set_nb) ;
00563     crires_image_save(set_tot,
00564             parlist,
00565             set, 
00566             flat, 
00567             recipe_name,
00568             CRIRES_CALPRO_FLAT, 
00569             CRIRES_PROTYPE_FLAT,
00570             crires_spec_flat_config.period,
00571             NULL,
00572             (const cpl_propertylist**)qclists, 
00573             PACKAGE "/" PACKAGE_VERSION,
00574             filename) ;
00575     cpl_free(filename) ;
00576 
00577     /* Write the BPM */
00578     if (bpm != NULL) {
00579         filename = cpl_sprintf("%s_set%02d_bpm.fits", recipe_name, set_nb) ;
00580         crires_image_save(set_tot,
00581                 parlist,
00582                 set, 
00583                 bpm, 
00584                 recipe_name,
00585                 CRIRES_CALPRO_BPM, 
00586                 CRIRES_PROTYPE_BPM,
00587                 crires_spec_flat_config.period,
00588                 NULL,
00589                 (const cpl_propertylist**)qclists, 
00590                 PACKAGE "/" PACKAGE_VERSION,
00591                 filename) ;
00592         cpl_free(filename) ;
00593     }
00594 
00595     /* Free and return */
00596     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00597         cpl_propertylist_delete(qclists[i]) ;
00598     }
00599     cpl_free(qclists) ;
00600     return  0;
00601 }
00602 
00603 /*----------------------------------------------------------------------------*/
00610 /*----------------------------------------------------------------------------*/
00611 static int crires_spec_flat_compare(
00612         const cpl_frame   *   frame1,
00613         const cpl_frame   *   frame2)
00614 {
00615     int                     comparison ;
00616     cpl_propertylist    *   plist1 ;
00617     cpl_propertylist    *   plist2 ;
00618     double                  dval1, dval2 ;
00619 
00620     /* Test entries */
00621     if (frame1==NULL || frame2==NULL) return -1 ;
00622 
00623     /* Get property lists */
00624     if ((plist1=cpl_propertylist_load(cpl_frame_get_filename(frame1),0))==NULL){
00625         cpl_msg_error(__func__, "getting header from reference frame");
00626         return -1 ;
00627     }
00628     if ((plist2=cpl_propertylist_load(cpl_frame_get_filename(frame2),0))==NULL){
00629         cpl_msg_error(__func__, "getting header from reference frame");
00630         cpl_propertylist_delete(plist1) ;
00631         return -1 ;
00632     }
00633 
00634     /* Test status */
00635     if (cpl_error_get_code()) {
00636         cpl_propertylist_delete(plist1) ;
00637         cpl_propertylist_delete(plist2) ;
00638         return -1 ;
00639     }
00640 
00641     comparison = 1 ;
00642 
00643     /* Compare the DIT used */
00644     dval1 = crires_pfits_get_dit(plist1) ;
00645     dval2 = crires_pfits_get_dit(plist2) ;
00646     if (cpl_error_get_code()) {
00647         cpl_msg_error(__func__, "Cannot get the DIT");
00648         cpl_propertylist_delete(plist1) ;
00649         cpl_propertylist_delete(plist2) ;
00650         return -1 ;
00651     }
00652     if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00653 
00654     /* Compare the WLEN REF used */
00655     dval1 = crires_pfits_get_refwlen(plist1) ;
00656     dval2 = crires_pfits_get_refwlen(plist2) ;
00657     if (cpl_error_get_code()) {
00658         cpl_msg_error(__func__, "Cannot get the reference wavelength");
00659         cpl_propertylist_delete(plist1) ;
00660         cpl_propertylist_delete(plist2) ;
00661         return -1 ;
00662     }
00663     if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00664 
00665     /* Compare the SHUT1 POS used */
00666     dval1 = crires_pfits_get_bafflepos(plist1) ;
00667     dval2 = crires_pfits_get_bafflepos(plist2) ;
00668     if (cpl_error_get_code()) {
00669         cpl_msg_error(__func__, "Cannot get the baffle position");
00670         cpl_propertylist_delete(plist1) ;
00671         cpl_propertylist_delete(plist2) ;
00672         return -1 ;
00673     }
00674     if (fabs(dval1-dval2) > 1e-3) comparison = 0 ;
00675 
00676     cpl_propertylist_delete(plist1) ;
00677     cpl_propertylist_delete(plist2) ;
00678     return comparison ;
00679 }
00680