CRIRES Pipeline Reference Manual  2.3.2
crires_spec_wavecal.c
00001 /* $Id: crires_spec_wavecal.c,v 1.75 2012-10-09 08:18:01 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-10-09 08:18:01 $
00024  * $Revision: 1.75 $
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 #include "crires_wlcalib.h"
00040 #include "crires_extract.h"
00041 #include "crires_model_kernel.h"
00042 
00043 /*-----------------------------------------------------------------------------
00044                                 Define
00045  -----------------------------------------------------------------------------*/
00046 
00047 #define RECIPE_STRING "crires_spec_wavecal"
00048 
00049 /*-----------------------------------------------------------------------------
00050                             Functions prototypes
00051  -----------------------------------------------------------------------------*/
00052 
00053 static int crires_spec_wavecal_save(const cpl_imagelist *, 
00054         const cpl_imagelist *, const cpl_table **, const cpl_parameterlist *, 
00055         cpl_frameset *) ;
00056 
00057 static char crires_spec_wavecal_description[] =
00058 "crires_spec_wavecal -- Wavelength calibration\n"
00059 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00060 "raw-file.fits "CRIRES_SPEC_WAVECAL_SKY_RAW" or\n"
00061 "raw-file.fits "CRIRES_SPEC_WAVECAL_LAMP_RAW" or\n" 
00062 "raw-file.fits "CRIRES_SPEC_WAVECAL_ABS_RAW" or\n" 
00063 "flat-file.fits "CRIRES_CALPRO_FLAT" or\n"
00064 "bpm-file.fits "CRIRES_CALPRO_BPM" or\n"
00065 "dark-file.fits "CRIRES_CALPRO_DARK" or\n"
00066 "detlin-file.fits "CRIRES_CALPRO_COEFFS_CUBE" or\n"
00067 "catalog-file.fits "CRIRES_CALPRO_THAR_CAT" or\n" 
00068 "catalog-file.fits "CRIRES_CALPRO_OH_CAT" or\n" 
00069 "catalog-file.fits "CRIRES_CALPRO_HITRAN_CAT" or\n" 
00070 "ypos-file.fits "CRIRES_CALPRO_THAR_POS" or\n" 
00071 "model-config-file.fits "CRIRES_CALPRO_MODEL_CONFIG".\n"
00072 "\n"
00073 "This recipe produces 3 files:\n"
00074 "First product:     the image with the wavelength values.\n"
00075 "                   (PRO TYPE = "CRIRES_PROTYPE_WL_MAP")\n"
00076 "Second product:    the image with the wavelength values from the model.\n"
00077 "                   (PRO TYPE = "CRIRES_PROTYPE_WL_MAP")\n"
00078 "Third product:     the table with the wavelength polynomial coefficients.\n"
00079 "                   (PRO TYPE = "CRIRES_PROTYPE_WL_POLY")\n" ;
00080 
00081 CRIRES_RECIPE_DEFINE(crires_spec_wavecal,
00082         CRIRES_PARAM_WAVES          |
00083         CRIRES_PARAM_DISPLAY        |
00084         CRIRES_PARAM_WL_LOG         |
00085         CRIRES_PARAM_WL_NOLIMIT     |
00086         CRIRES_PARAM_WL_ERROR       |
00087         CRIRES_PARAM_XC_LIMIT       |
00088         CRIRES_PARAM_WL_NBSAMPLES   |
00089         CRIRES_PARAM_Y_POS_CHIP1    |
00090         CRIRES_PARAM_Y_POS_CHIP2    |
00091         CRIRES_PARAM_Y_POS_CHIP3    |
00092         CRIRES_PARAM_Y_POS_CHIP4    |
00093         CRIRES_PARAM_Y_WIDTH        |
00094         CRIRES_PARAM_DEGREE         |
00095         CRIRES_PARAM_WL_CLEAN,
00096         "Wavelength calibration",
00097         crires_spec_wavecal_description) ;
00098 
00099 /*-----------------------------------------------------------------------------
00100                             Static variables
00101  -----------------------------------------------------------------------------*/
00102 
00103 static struct {
00104     /* Inputs */
00105     double              wstart[CRIRES_NB_DETECTORS] ;
00106     double              wstop[CRIRES_NB_DETECTORS] ;
00107     int                 wl_nolimit ;
00108     int                 wl_log ;
00109     const char      *   wl_ypos_c1 ;
00110     const char      *   wl_ypos_c2 ;
00111     const char      *   wl_ypos_c3 ;
00112     const char      *   wl_ypos_c4 ;
00113     int                 wl_width ;
00114     double              wl_fwhm ;
00115     double              wl_slitw ;
00116     int                 wl_degree ;
00117     double              wl_err ;
00118     int                 wl_samples ;
00119     int                 wl_clean ;
00120     double              wl_xclimit ;
00121     int                 wl_ppm ;
00122     int                 display ;
00123     /* Outputs */
00124     crires_illum_period period ;
00125     int                 mode ;
00126     double              qc_wlxc[CRIRES_NB_DETECTORS] ;
00127     double              qc_wlcent[CRIRES_NB_DETECTORS] ;
00128     double              qc_wldisp[CRIRES_NB_DETECTORS] ;
00129     double              qc_lines_flux[CRIRES_NB_DETECTORS] ;
00130     double              qc_fwhm[CRIRES_NB_DETECTORS] ;
00131     double              qc_rpower[CRIRES_NB_DETECTORS] ;
00132 } crires_spec_wavecal_config ;
00133 
00134 /*-----------------------------------------------------------------------------
00135                                 Functions code
00136  -----------------------------------------------------------------------------*/
00137 
00138 /*----------------------------------------------------------------------------*/
00145 /*----------------------------------------------------------------------------*/
00146 static int crires_spec_wavecal(
00147         cpl_frameset            *   frameset,
00148         const cpl_parameterlist *   parlist)
00149 {
00150     const char          *   sval ;
00151     const char          *   wl_ypos ;
00152     cpl_frameset        *   rawframes ;
00153     const char          *   fname ;
00154     const char          *   flat ;
00155     const char          *   dark ;
00156     const char          *   bpm ;
00157     const char          *   detlin ;
00158     const char          *   thar_cat ;
00159     const char          *   n2o_cat ;
00160     const char          *   oh_cat ;
00161     const char          *   hitran_cat ;
00162     const char          *   cfg_model ;
00163     const char          *   thar_positions ;
00164     cpl_propertylist    *   plist ;
00165     double                  wmin, wmax ;
00166     cpl_table           *   wave_tab[CRIRES_NB_DETECTORS] ;
00167     cpl_imagelist       *   wl_map ;
00168     cpl_imagelist       *   wl_map_model ;
00169     cpl_vector          *   wave_ypos ;
00170     int                     pix ;
00171     int                     i, j ;
00172 
00173     /* Initialise */
00174     rawframes = NULL ;
00175     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00176         crires_spec_wavecal_config.qc_wlxc[i] = -1.0 ;
00177         crires_spec_wavecal_config.qc_wlcent[i] = -1.0 ;
00178         crires_spec_wavecal_config.qc_wldisp[i] = -1.0 ;
00179         crires_spec_wavecal_config.qc_lines_flux[i] = -1.0 ;
00180         crires_spec_wavecal_config.qc_fwhm[i] = -1.0 ;
00181         crires_spec_wavecal_config.qc_rpower[i] = -1.0 ;
00182     }
00183     crires_spec_wavecal_config.wl_ppm = 0 ;
00184     crires_spec_wavecal_config.wl_slitw = 2.0 ;
00185     crires_spec_wavecal_config.wl_fwhm = 2.0 ;
00186     
00187     /* Retrieve input parameters */
00188 
00189     sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
00190             CRIRES_PARAM_WAVES) ;
00191     if (sscanf(sval, "%lg,%lg,%lg,%lg,%lg,%lg,%lg,%lg",
00192                     &crires_spec_wavecal_config.wstart[0],
00193                     &crires_spec_wavecal_config.wstop[0],
00194                     &crires_spec_wavecal_config.wstart[1],
00195                     &crires_spec_wavecal_config.wstop[1],
00196                     &crires_spec_wavecal_config.wstart[2],
00197                     &crires_spec_wavecal_config.wstop[2],
00198                     &crires_spec_wavecal_config.wstart[3],
00199                     &crires_spec_wavecal_config.wstop[3])!=2*CRIRES_NB_DETECTORS){
00200         return -1 ;
00201     }
00202     crires_spec_wavecal_config.display = crires_parameterlist_get_int(parlist,
00203             RECIPE_STRING, CRIRES_PARAM_DISPLAY) ;
00204     crires_spec_wavecal_config.wl_log = crires_parameterlist_get_bool(parlist,
00205             RECIPE_STRING, CRIRES_PARAM_WL_LOG) ;
00206     crires_spec_wavecal_config.wl_nolimit = crires_parameterlist_get_bool(
00207             parlist, RECIPE_STRING, CRIRES_PARAM_WL_NOLIMIT) ;
00208     crires_spec_wavecal_config.wl_degree = crires_parameterlist_get_int(parlist,
00209             RECIPE_STRING, CRIRES_PARAM_DEGREE) ;
00210     crires_spec_wavecal_config.wl_err = crires_parameterlist_get_double(parlist,
00211             RECIPE_STRING, CRIRES_PARAM_WL_ERROR) ;
00212     crires_spec_wavecal_config.wl_xclimit = crires_parameterlist_get_double(
00213             parlist, RECIPE_STRING, CRIRES_PARAM_XC_LIMIT) ;
00214     crires_spec_wavecal_config.wl_ypos_c1=crires_parameterlist_get_string(
00215             parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP1) ;
00216     crires_spec_wavecal_config.wl_ypos_c2=crires_parameterlist_get_string(
00217             parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP2) ;
00218     crires_spec_wavecal_config.wl_ypos_c3=crires_parameterlist_get_string(
00219             parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP3) ;
00220     crires_spec_wavecal_config.wl_ypos_c4=crires_parameterlist_get_string(
00221             parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP4) ;
00222     crires_spec_wavecal_config.wl_width= crires_parameterlist_get_int(parlist,
00223             RECIPE_STRING, CRIRES_PARAM_Y_WIDTH) ;
00224     crires_spec_wavecal_config.wl_samples = crires_parameterlist_get_int(
00225             parlist, RECIPE_STRING, CRIRES_PARAM_WL_NBSAMPLES) ;
00226     crires_spec_wavecal_config.wl_clean = crires_parameterlist_get_bool(parlist,
00227             RECIPE_STRING, CRIRES_PARAM_WL_CLEAN) ;
00228 
00229     /* Identify the RAW and CALIB frames in the input frameset */
00230     if (crires_dfs_set_groups(frameset, "crires_spec_wavecal")) {
00231         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00232         return -1 ;
00233     }
00234 
00235     /* Retrieve calibration data */
00236     flat        = crires_extract_filename(frameset, CRIRES_CALPRO_FLAT) ;
00237     dark        = crires_extract_filename(frameset, CRIRES_CALPRO_DARK) ;
00238     bpm         = crires_extract_filename(frameset, CRIRES_CALPRO_BPM) ;
00239     detlin      = crires_extract_filename(frameset, CRIRES_CALPRO_COEFFS_CUBE) ;
00240     thar_cat = crires_extract_filename(frameset, CRIRES_CALPRO_THAR_CAT) ;
00241     n2o_cat = crires_extract_filename(frameset, CRIRES_CALPRO_N2O_CAT) ;
00242     oh_cat = crires_extract_filename(frameset, CRIRES_CALPRO_OH_CAT) ;
00243     hitran_cat = crires_extract_filename(frameset, CRIRES_CALPRO_HITRAN_CAT) ;
00244     cfg_model = crires_extract_filename(frameset, CRIRES_CALPRO_MODEL_CONFIG) ;
00245     thar_positions = crires_extract_filename(frameset, CRIRES_CALPRO_THAR_POS) ;
00246     
00247     /* Retrieve raw frames */
00248     if ((rawframes = crires_extract_frameset(frameset,
00249                     CRIRES_SPEC_WAVECAL_SKY_RAW)) != NULL) {
00250         crires_spec_wavecal_config.mode = 1 ;
00251     } else if ((rawframes = crires_extract_frameset(frameset, 
00252                     CRIRES_SPEC_WAVECAL_LAMP_RAW)) != NULL) {
00253         crires_spec_wavecal_config.mode = 2 ;
00254     } else if ((rawframes = crires_extract_frameset(frameset, 
00255                     CRIRES_SPEC_WAVECAL_ABS_RAW)) != NULL) {
00256         crires_spec_wavecal_config.mode = 3 ;
00257     } else {
00258         cpl_msg_error(__func__, "No raw frame in input") ;
00259         return -1 ;
00260     }
00261 
00262     /* Get the detector illumination period */
00263     crires_spec_wavecal_config.period =
00264         crires_get_detector_illum_period(
00265             cpl_frame_get_filename(cpl_frameset_get_position(rawframes, 0))) ;
00266     if (crires_spec_wavecal_config.period == CRIRES_ILLUM_UNKNOWN) {
00267         cpl_msg_error(__func__,
00268                 "Cannot determine the detector illumination period") ;
00269         cpl_frameset_delete(rawframes) ;
00270         return -1 ;
00271     } else {
00272         crires_display_detector_illum(crires_spec_wavecal_config.period) ;
00273     }
00274 
00275     /* Reduce the first raw frame */
00276     fname = cpl_frame_get_filename(cpl_frameset_get_position(rawframes,0)) ;
00277 
00278     /* Get the Minimum and Maximum wavelengths */
00279     if (crires_spec_wavecal_config.wl_nolimit == 0) {
00280         plist = cpl_propertylist_load(fname, 0) ;
00281         wmin = crires_pfits_get_wlen_min(plist) ;
00282         wmax = crires_pfits_get_wlen_max(plist) ;
00283         cpl_propertylist_delete(plist) ;
00284         if (cpl_error_get_code()) {
00285             wmin = wmax = -1.0 ;
00286             cpl_error_reset() ;
00287         }
00288     } else {
00289         wmin = wmax = -1.0 ;
00290     }
00291    
00292     /* Wavelength calibration */
00293     cpl_msg_info(__func__, "Apply the Wavelength Calibration") ;
00294     cpl_msg_indent_more() ;
00295     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00296         cpl_msg_info(__func__, "Calibrate chip number %d", i+1) ;
00297         cpl_msg_indent_more() ;
00298 
00299         /* Where Compute the wavelength from ? */
00300         wl_ypos = "" ;
00301         if (i+1 == 1) wl_ypos = crires_spec_wavecal_config.wl_ypos_c1 ;
00302         if (i+1 == 2) wl_ypos = crires_spec_wavecal_config.wl_ypos_c2 ;
00303         if (i+1 == 3) wl_ypos = crires_spec_wavecal_config.wl_ypos_c3 ;
00304         if (i+1 == 4) wl_ypos = crires_spec_wavecal_config.wl_ypos_c4 ;
00305 
00306         /* Try to parse the user specified positions */
00307         if (!strcmp(wl_ypos, "")) {
00308             wave_ypos = NULL ;
00309         } else {
00310             cpl_msg_info(__func__, 
00311                     "Use the Y positions provided on the command line") ;
00312             if ((wave_ypos = crires_parse_y_positions(wl_ypos)) == NULL) {
00313                 cpl_msg_warning(__func__,
00314                         "Cannot parse the y_positions value : %s", wl_ypos) ;
00315             }
00316         }
00317         
00318         /* Otherwise use passed calibration file */
00319         if (wave_ypos == NULL && thar_positions != NULL) {
00320             cpl_msg_info(__func__, 
00321                     "Use the Y positions provided in the FITS file") ;
00322             if ((wave_ypos = crires_read_y_positions(thar_positions, 
00323                             i+1)) == NULL) {
00324                 cpl_msg_warning(__func__,
00325                         "Cannot read the Y positions from file %s", 
00326                         thar_positions) ;
00327             }
00328         }
00329 
00330         /* Try to detect the positions */
00331         if (wave_ypos == NULL) {
00332             cpl_msg_info(__func__, 
00333                     "Try an automatic detection of the Y positions") ;
00334             wave_ypos = crires_wlcalib_detect_wave_ypos(fname, 
00335                     crires_spec_wavecal_config.period, i+1);
00336         }
00337 
00338         /* Check the Mode */
00339         if (crires_spec_wavecal_config.mode == 1) {
00340             /* Calibrate from the sky */
00341             cpl_msg_info(__func__,"Get the calibration from the oh/hitran sky");
00342             wave_tab[i] = crires_wlcalib_sky(fname,
00343                     crires_spec_wavecal_config.period,
00344                     oh_cat, hitran_cat, crires_spec_wavecal_config.wl_log,
00345                     flat, dark, bpm, detlin,
00346                     crires_spec_wavecal_config.wstart[i],
00347                     crires_spec_wavecal_config.wstop[i],
00348                     wmin, wmax, i+1, 
00349                     wave_ypos,
00350                     crires_spec_wavecal_config.wl_width,
00351                     crires_spec_wavecal_config.wl_degree,
00352                     crires_spec_wavecal_config.wl_slitw,
00353                     crires_spec_wavecal_config.wl_fwhm,
00354                     crires_spec_wavecal_config.wl_err,
00355                     crires_spec_wavecal_config.wl_samples,
00356                     crires_spec_wavecal_config.wl_clean,
00357                     crires_spec_wavecal_config.wl_xclimit,
00358                     crires_spec_wavecal_config.wl_ppm,
00359                     (i+1==crires_spec_wavecal_config.display)) ;
00360         } else if (crires_spec_wavecal_config.mode == 2) {
00361             /* Calibrate from the lamp */
00362             cpl_msg_info(__func__, "Get the calibration from the thar lamp") ;
00363             wave_tab[i] = crires_wlcalib_lamp(fname,
00364                     crires_spec_wavecal_config.period,
00365                     thar_cat, crires_spec_wavecal_config.wl_log,
00366                     flat, dark, bpm, detlin,
00367                     crires_spec_wavecal_config.wstart[i],
00368                     crires_spec_wavecal_config.wstop[i],
00369                     wmin, wmax, i+1,
00370                     wave_ypos,
00371                     crires_spec_wavecal_config.wl_width,
00372                     crires_spec_wavecal_config.wl_degree,
00373                     crires_spec_wavecal_config.wl_slitw,
00374                     crires_spec_wavecal_config.wl_fwhm,
00375                     crires_spec_wavecal_config.wl_err,
00376                     crires_spec_wavecal_config.wl_samples,
00377                     crires_spec_wavecal_config.wl_clean,
00378                     crires_spec_wavecal_config.wl_xclimit,
00379                     crires_spec_wavecal_config.wl_ppm,
00380                     (i+1==crires_spec_wavecal_config.display),
00381                     &(crires_spec_wavecal_config.qc_lines_flux[i]),
00382                     &(crires_spec_wavecal_config.qc_fwhm[i]),
00383                     &(crires_spec_wavecal_config.qc_rpower[i])) ;
00384         } else if (crires_spec_wavecal_config.mode == 3) {
00385             /* Calibrate from the gas cell */
00386             cpl_msg_info(__func__, "Get the calibration from the n2o gas cell");
00387             wave_tab[i] = crires_wlcalib_lamp(fname,
00388                     crires_spec_wavecal_config.period,
00389                     n2o_cat, crires_spec_wavecal_config.wl_log, 
00390                     flat, dark, bpm, detlin,
00391                     crires_spec_wavecal_config.wstart[i],
00392                     crires_spec_wavecal_config.wstop[i],
00393                     wmin, wmax, i+1,
00394                     wave_ypos,
00395                     crires_spec_wavecal_config.wl_width,
00396                     crires_spec_wavecal_config.wl_degree,
00397                     crires_spec_wavecal_config.wl_slitw,
00398                     crires_spec_wavecal_config.wl_fwhm,
00399                     crires_spec_wavecal_config.wl_err,
00400                     crires_spec_wavecal_config.wl_samples,
00401                     crires_spec_wavecal_config.wl_clean,
00402                     crires_spec_wavecal_config.wl_xclimit,
00403                     crires_spec_wavecal_config.wl_ppm,
00404                     (i+1==crires_spec_wavecal_config.display),
00405                     &(crires_spec_wavecal_config.qc_lines_flux[i]), 
00406                     &(crires_spec_wavecal_config.qc_fwhm[i]),
00407                     &(crires_spec_wavecal_config.qc_rpower[i])) ;
00408         }
00409         cpl_msg_indent_less() ;
00410     cpl_vector_delete(wave_ypos) ;
00411     }
00412     cpl_msg_indent_less() ;
00413 
00414     /* Create the wave map */
00415     if ((wl_map = crires_wlcalib_gen_wlmap((const cpl_table **)wave_tab))
00416             == NULL) {
00417         cpl_msg_error(__func__, "Cannot compute the Wavelength Map") ;
00418         cpl_frameset_delete(rawframes) ;
00419         for (j=0 ; j<CRIRES_NB_DETECTORS ; j++) {
00420             if (wave_tab[j] != NULL) cpl_table_delete(wave_tab[j]);
00421         }
00422         return -1 ;
00423     }
00424 
00425     /* Compute the QC parameters */
00426     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00427         crires_spec_wavecal_config.qc_wlcent[i] =
00428             cpl_image_get(cpl_imagelist_get(wl_map, i),
00429                     512, 256, &pix) ;
00430         crires_spec_wavecal_config.qc_wldisp[i] =
00431             ((cpl_image_get(cpl_imagelist_get(wl_map, i), 1024,
00432                             256, &pix)) -
00433              (cpl_image_get(cpl_imagelist_get(wl_map, i), 1,
00434                             256, &pix)))
00435             / 1023 ;
00436         crires_spec_wavecal_config.qc_wlxc[i] =
00437             crires_wlcalib_get_better_xc(wave_tab[i]) ;
00438     }
00439 
00440     /* Get the wl map from the model */
00441     if ((cfg_model != NULL) && (!crires_model_off()) && 
00442             (crires_model_config_check(cfg_model, fname) == 0)) {
00443         cpl_msg_info(__func__, "Call the model to get the wavelength map") ;
00444         cpl_msg_indent_more() ;
00445         wl_map_model = crires_model_wavpix(fname, cfg_model, -1) ;
00446         if (wl_map_model == NULL) {
00447             cpl_msg_warning(__func__, "Model function returns NULL") ;
00448             cpl_error_reset() ;
00449         }
00450         cpl_msg_indent_less() ;
00451     } else {
00452         wl_map_model = NULL ;
00453     }
00454     cpl_frameset_delete(rawframes) ;
00455     
00456     /* Save the product */
00457     cpl_msg_info(__func__, "Save the product") ;
00458     cpl_msg_indent_more() ;
00459     if (crires_spec_wavecal_save(wl_map, wl_map_model, 
00460                 (const cpl_table **)wave_tab, parlist, frameset)) {
00461         cpl_msg_error(__func__, "Cannot save the product") ;
00462         for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) 
00463             if (wave_tab[i] != NULL) cpl_table_delete(wave_tab[i]);
00464         cpl_imagelist_delete(wl_map) ;
00465         if (wl_map_model) cpl_imagelist_delete(wl_map_model) ;
00466         cpl_msg_indent_less() ;
00467         return -1 ;
00468     }
00469     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++)
00470         if (wave_tab[i] != NULL) cpl_table_delete(wave_tab[i]);
00471     cpl_imagelist_delete(wl_map) ;
00472     if (wl_map_model) cpl_imagelist_delete(wl_map_model) ;
00473     cpl_msg_indent_less() ;
00474 
00475     /* Return */
00476     if (cpl_error_get_code()) return -1 ;
00477     else return 0 ;
00478 }
00479 
00480 /*----------------------------------------------------------------------------*/
00490 /*----------------------------------------------------------------------------*/
00491 static int crires_spec_wavecal_save(
00492         const cpl_imagelist     *   ilist,
00493         const cpl_imagelist     *   ilist_model,
00494         const cpl_table         **  wl_tab,
00495         const cpl_parameterlist *   parlist,
00496         cpl_frameset            *   set)
00497 {
00498     cpl_propertylist    **  qclists ;
00499     const cpl_frame     *   ref_frame ;
00500     cpl_propertylist    *   inputlist ;
00501     const char          *   recipe_name = "crires_spec_wavecal" ;
00502     int                     i ;
00503 
00504     /* Get the reference frame */
00505     ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
00506 
00507     /* Create the QC lists */
00508     qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
00509     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00510         qclists[i] = cpl_propertylist_new() ;
00511         cpl_propertylist_append_double(qclists[i], "ESO QC CENTWL",
00512                 crires_spec_wavecal_config.qc_wlcent[i]) ;
00513         cpl_propertylist_append_double(qclists[i], "ESO QC DISPWL",
00514                 crires_spec_wavecal_config.qc_wldisp[i]) ;
00515         cpl_propertylist_append_double(qclists[i], "ESO QC XCORR",
00516                 crires_spec_wavecal_config.qc_wlxc[i]) ;
00517         cpl_propertylist_append_double(qclists[i], "ESO QC LINES FLUX",
00518                 crires_spec_wavecal_config.qc_lines_flux[i]) ;
00519         cpl_propertylist_append_double(qclists[i], "ESO QC FWHM MED",
00520                 crires_spec_wavecal_config.qc_fwhm[i]) ;
00521         cpl_propertylist_append_double(qclists[i], "ESO QC RESOL MED",
00522                 crires_spec_wavecal_config.qc_rpower[i]) ;
00523 
00524         /* Propagate some keywords from input raw frame extensions */
00525         inputlist = cpl_propertylist_load_regexp(
00526                 cpl_frame_get_filename(ref_frame), i+1,
00527                 CRIRES_HEADER_EXT_FORWARD, 0) ;
00528         cpl_propertylist_copy_property_regexp(qclists[i], inputlist,
00529                 CRIRES_HEADER_EXT_FORWARD, 0) ;
00530         cpl_propertylist_delete(inputlist) ;
00531     }
00532 
00533     /* Write the image */
00534     crires_image_save(set,
00535             parlist,
00536             set,
00537             ilist,
00538             recipe_name,
00539             CRIRES_WL_MAP_IMA,
00540             CRIRES_PROTYPE_WL_MAP,
00541             crires_spec_wavecal_config.period,
00542             NULL,
00543             (const cpl_propertylist **)qclists,
00544             PACKAGE "/" PACKAGE_VERSION,
00545             "crires_spec_wavecal_ima.fits") ;
00546 
00547     if (ilist_model != NULL) {
00548         /* Write the image */
00549         crires_image_save(set,
00550                 parlist,
00551                 set,
00552                 ilist_model,
00553                 recipe_name,
00554                 CRIRES_WL_MAP_MODEL_IMA,
00555                 CRIRES_PROTYPE_WL_MAP,
00556                 crires_spec_wavecal_config.period,
00557                 NULL,
00558                 (const cpl_propertylist **)qclists,
00559                 PACKAGE "/" PACKAGE_VERSION,
00560                 "crires_spec_wavecal_ima_model.fits") ;
00561     }
00562 
00563     /* Write the table */
00564     crires_table_save(set,
00565             parlist,
00566             set, 
00567             wl_tab, 
00568             recipe_name,
00569             CRIRES_CALPRO_WAVE, 
00570             CRIRES_PROTYPE_WL_POLY,
00571             NULL,
00572             (const cpl_propertylist **)qclists, 
00573             PACKAGE "/" PACKAGE_VERSION,
00574             "crires_spec_wavecal_tab.fits") ;
00575 
00576     /* Free and return */
00577     for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
00578         cpl_propertylist_delete(qclists[i]) ;
00579     }
00580     cpl_free(qclists) ;
00581     return  0;
00582 }