vimos_calib_impl.c

00001 /* $Id: vimos_calib_impl.c,v 1.2 2010/09/14 07:49:30 cizzo Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cizzo $
00023  * $Date: 2010/09/14 07:49:30 $
00024  * $Revision: 1.2 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <vimos_calib_impl.h>
00033 
00034 #include <math.h>
00035 #include <cpl.h>
00036 #include <moses.h>
00037 #include <fors_dfs.h>
00038 #include <fors_qc.h>
00039 
00040 #define vimos_calib_exit(message)             \
00041 {                                             \
00042 if (message) cpl_msg_error(recipe, message);  \
00043 cpl_free(instrume);                           \
00044 cpl_free(pipefile);                           \
00045 cpl_free(fiterror);                           \
00046 cpl_free(fitlines);                           \
00047 cpl_image_delete(bias);                       \
00048 cpl_image_delete(master_bias);                \
00049 cpl_image_delete(coordinate);                 \
00050 cpl_image_delete(checkwave);                  \
00051 cpl_image_delete(flat);                       \
00052 cpl_image_delete(master_flat);                \
00053 cpl_image_delete(norm_flat);                  \
00054 cpl_image_delete(rainbow);                    \
00055 cpl_image_delete(rectified);                  \
00056 cpl_image_delete(residual);                   \
00057 cpl_image_delete(smo_flat);                   \
00058 cpl_image_delete(spatial);                    \
00059 cpl_image_delete(spectra);                    \
00060 cpl_image_delete(wavemap);                    \
00061 cpl_image_delete(delta);                      \
00062 cpl_mask_delete(refmask);                     \
00063 cpl_propertylist_delete(header);              \
00064 cpl_propertylist_delete(save_header);         \
00065 cpl_propertylist_delete(qclist);              \
00066 cpl_table_delete(grism_table);                \
00067 cpl_table_delete(idscoeff);                   \
00068 cpl_table_delete(restable);                   \
00069 cpl_table_delete(maskslits);                  \
00070 cpl_table_delete(overscans);                  \
00071 cpl_table_delete(traces);                     \
00072 cpl_table_delete(polytraces);                 \
00073 cpl_table_delete(slits);                      \
00074 cpl_table_delete(restab);                     \
00075 cpl_table_delete(global);                     \
00076 cpl_table_delete(wavelengths);                \
00077 cpl_vector_delete(lines);                     \
00078 cpl_msg_indent_less();                        \
00079 return -1;                                    \
00080 }
00081 
00082 #define vimos_calib_exit_memcheck(message)       \
00083 {                                               \
00084 if (message) cpl_msg_info(recipe, message);     \
00085 printf("free instrume (%p)\n", instrume);       \
00086 cpl_free(instrume);                             \
00087 printf("free pipefile (%p)\n", pipefile);       \
00088 cpl_free(pipefile);                             \
00089 printf("free fiterror (%p)\n", fiterror);       \
00090 cpl_free(fiterror);                             \
00091 printf("free fitlines (%p)\n", fitlines);       \
00092 cpl_free(fitlines);                             \
00093 printf("free bias (%p)\n", bias);               \
00094 cpl_image_delete(bias);                         \
00095 printf("free master_bias (%p)\n", master_bias); \
00096 cpl_image_delete(master_bias);                  \
00097 printf("free coordinate (%p)\n", coordinate);   \
00098 cpl_image_delete(coordinate);                   \
00099 printf("free checkwave (%p)\n", checkwave);     \
00100 cpl_image_delete(checkwave);                    \
00101 printf("free flat (%p)\n", flat);               \
00102 cpl_image_delete(flat);                         \
00103 printf("free master_flat (%p)\n", master_flat); \
00104 cpl_image_delete(master_flat);                  \
00105 printf("free norm_flat (%p)\n", norm_flat);     \
00106 cpl_image_delete(norm_flat);                    \
00107 printf("free rainbow (%p)\n", rainbow);         \
00108 cpl_image_delete(rainbow);                      \
00109 printf("free rectified (%p)\n", rectified);     \
00110 cpl_image_delete(rectified);                    \
00111 printf("free residual (%p)\n", residual);       \
00112 cpl_image_delete(residual);                     \
00113 printf("free smo_flat (%p)\n", smo_flat);       \
00114 cpl_image_delete(smo_flat);                     \
00115 printf("free spatial (%p)\n", spatial);         \
00116 cpl_image_delete(spatial);                      \
00117 printf("free spectra (%p)\n", spectra);         \
00118 cpl_image_delete(spectra);                      \
00119 printf("free wavemap (%p)\n", wavemap);         \
00120 cpl_image_delete(wavemap);                      \
00121 printf("free delta (%p)\n", delta);             \
00122 cpl_image_delete(delta);                        \
00123 printf("free refmask (%p)\n", refmask);         \
00124 cpl_mask_delete(refmask);                       \
00125 printf("free header (%p)\n", header);           \
00126 cpl_propertylist_delete(header);                \
00127 printf("free save_header (%p)\n", save_header); \
00128 cpl_propertylist_delete(save_header);           \
00129 printf("free qclist (%p)\n", qclist);           \
00130 cpl_propertylist_delete(qclist);                \
00131 printf("free grism_table (%p)\n", grism_table); \
00132 cpl_table_delete(grism_table);                  \
00133 printf("free idscoeff (%p)\n", idscoeff);       \
00134 cpl_table_delete(idscoeff);                     \
00135 printf("free restable (%p)\n", restable);       \
00136 cpl_table_delete(restable);                     \
00137 printf("free maskslits (%p)\n", maskslits);     \
00138 cpl_table_delete(maskslits);                    \
00139 printf("free overscans (%p)\n", overscans);     \
00140 cpl_table_delete(overscans);                    \
00141 printf("free traces (%p)\n", traces);           \
00142 cpl_table_delete(traces);                       \
00143 printf("free polytraces (%p)\n", polytraces);   \
00144 cpl_table_delete(polytraces);                   \
00145 printf("free slits (%p)\n", slits);             \
00146 cpl_table_delete(slits);                        \
00147 printf("free restab (%p)\n", restab);           \
00148 cpl_table_delete(restab);                       \
00149 printf("free global (%p)\n", global);           \
00150 cpl_table_delete(global);                       \
00151 printf("free wavelengths (%p)\n", wavelengths); \
00152 cpl_table_delete(wavelengths);                  \
00153 printf("free lines (%p)\n", lines);             \
00154 cpl_vector_delete(lines);                       \
00155 cpl_msg_indent_less();                          \
00156 return 0;                                       \
00157 }
00158 
00174 int vimos_calib_impl(cpl_frameset *frameset, cpl_parameterlist *parlist)
00175 {
00176 
00177     const char *recipe = "vimos_calib";
00178 
00179     /*
00180      * Input parameters
00181      */
00182 
00183     double      dispersion;
00184     double      peakdetection;
00185     int         wdegree;
00186     int         wradius;
00187     double      wreject;
00188     int         wmode;
00189     const char *wcolumn;
00190     int         cdegree;
00191     int         cmode;
00192     double      startwavelength;
00193     double      endwavelength;
00194     double      reference;
00195     int         slit_ident;
00196     int         sdegree;
00197     int         ddegree;
00198     int         sradius;
00199     int         dradius;
00200     int         qc;
00201     int         check;
00202 
00203     /*
00204      * CPL objects
00205      */
00206 
00207     cpl_imagelist    *biases      = NULL;
00208     cpl_image        *bias        = NULL;
00209     cpl_image        *master_bias = NULL;
00210     cpl_image        *multi_bias  = NULL;
00211     cpl_image        *flat        = NULL;
00212     cpl_image        *master_flat = NULL;
00213     cpl_image        *smo_flat    = NULL;
00214     cpl_image        *norm_flat   = NULL;
00215     cpl_image        *spectra     = NULL;
00216     cpl_image        *wavemap     = NULL;
00217     cpl_image        *delta       = NULL;
00218     cpl_image        *residual    = NULL;
00219     cpl_image        *checkwave   = NULL;
00220     cpl_image        *rectified   = NULL;
00221     cpl_image        *dummy       = NULL;
00222     cpl_image        *refimage    = NULL;
00223     cpl_image        *coordinate  = NULL;
00224     cpl_image        *rainbow     = NULL;
00225     cpl_image        *spatial     = NULL;
00226 
00227     cpl_mask         *refmask     = NULL;
00228 
00229     cpl_table        *grism_table = NULL;
00230     cpl_table        *overscans   = NULL;
00231     cpl_table        *wavelengths = NULL;
00232     cpl_table        *idscoeff    = NULL;
00233     cpl_table        *restable    = NULL;
00234     cpl_table        *slits       = NULL;
00235     cpl_table        *positions   = NULL;
00236     cpl_table        *maskslits   = NULL;
00237     cpl_table        *traces      = NULL;
00238     cpl_table        *polytraces  = NULL;
00239     cpl_table        *restab      = NULL;
00240     cpl_table        *global      = NULL;
00241 
00242     cpl_vector       *lines       = NULL;
00243 
00244     cpl_propertylist *header      = NULL;
00245     cpl_propertylist *save_header = NULL;
00246     cpl_propertylist *qclist      = NULL;
00247 
00248     /*
00249      * Auxiliary variables
00250      */
00251 
00252     cpl_table  *idscoeff_lss = NULL;
00253     char        version[80];
00254     const char *arc_tag;
00255     const char *flat_tag;
00256     const char *master_screen_flat_tag;
00257     const char *master_norm_flat_tag;
00258     const char *reduced_lamp_tag;
00259     const char *disp_residuals_tag;
00260     const char *disp_coeff_tag;
00261     const char *wavelength_map_tag;
00262     const char *spectra_detection_tag;
00263     const char *spectral_resolution_tag;
00264     const char *slit_map_tag;
00265     const char *curv_traces_tag;
00266     const char *curv_coeff_tag;
00267     const char *spatial_map_tag;
00268     const char *slit_location_tag;
00269     const char *global_distortion_tag = "GLOBAL_DISTORTION_TABLE";
00270     const char *disp_residuals_table_tag;
00271     const char *delta_image_tag;
00272     const char *key_gris_name;
00273     const char *key_gris_id;
00274     const char *key_filt_name;
00275     const char *key_filt_id;
00276     const char *key_mask_id;
00277     char       *keyname;
00278     int         quadrant;
00279     int         mos;
00280     int         treat_as_lss = 0;
00281     int         nslits;
00282     double     *xpos;
00283     double      mxpos;
00284     double      mean_rms;
00285     double      alltime, arctime;
00286     int         nflats;
00287     int         nbias;
00288     int         nlines;
00289     double     *line;
00290     double     *fiterror = NULL;
00291     int        *fitlines = NULL;
00292     int         nx, ny;
00293     double      gain;
00294     int         ccd_xsize, ccd_ysize;
00295     int         rotate = 1;
00296     int         rotate_back = -1;
00297     int         i;
00298 
00299     char       *instrume = NULL;
00300     char       *pipefile = NULL;
00301     char       *grism;
00302 
00303 
00304     snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00305 
00306     cpl_msg_set_indentation(2);
00307 
00308     if (dfs_files_dont_exist(frameset))
00309         vimos_calib_exit(NULL);
00310 
00311 
00312     /* 
00313      * Get configuration parameters
00314      */
00315 
00316     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00317     cpl_msg_indent_more();
00318 
00319     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00320         vimos_calib_exit("Too many in input: GRISM_TABLE");
00321 
00322     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00323 
00324     dispersion = dfs_get_parameter_double(parlist, 
00325                     "fors.vimos_calib.dispersion", grism_table);
00326 
00327     if (dispersion <= 0.0)
00328         vimos_calib_exit("Invalid spectral dispersion value");
00329 
00330     peakdetection = dfs_get_parameter_double(parlist, 
00331                     "fors.vimos_calib.peakdetection", grism_table);
00332     if (peakdetection <= 0.0)
00333         vimos_calib_exit("Invalid peak detection level");
00334 
00335     wdegree = dfs_get_parameter_int(parlist, 
00336                     "fors.vimos_calib.wdegree", grism_table);
00337 
00338     if (wdegree < 1)
00339         vimos_calib_exit("Invalid polynomial degree");
00340 
00341     if (wdegree > 5)
00342         vimos_calib_exit("Max allowed polynomial degree is 5");
00343 
00344     wradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.wradius", NULL);
00345 
00346     if (wradius < 0)
00347         vimos_calib_exit("Invalid search radius");
00348 
00349     wreject = dfs_get_parameter_double(parlist, 
00350                                        "fors.vimos_calib.wreject", NULL);
00351 
00352     if (wreject <= 0.0)
00353         vimos_calib_exit("Invalid rejection threshold");
00354 
00355     wmode = dfs_get_parameter_int(parlist, "fors.vimos_calib.wmode", NULL);
00356 
00357     if (wmode < 0 || wmode > 2)
00358         vimos_calib_exit("Invalid wavelength solution interpolation mode");
00359 
00360     wcolumn = dfs_get_parameter_string(parlist, 
00361                                        "fors.vimos_calib.wcolumn", NULL);
00362 
00363     cdegree = dfs_get_parameter_int(parlist, 
00364                     "fors.vimos_calib.cdegree", grism_table);
00365 
00366     if (cdegree < 1)
00367         vimos_calib_exit("Invalid polynomial degree");
00368 
00369     if (cdegree > 5)
00370         vimos_calib_exit("Max allowed polynomial degree is 5");
00371 
00372     cmode = dfs_get_parameter_int(parlist, "fors.vimos_calib.cmode", NULL);
00373 
00374     if (cmode < 0 || cmode > 2)
00375         vimos_calib_exit("Invalid curvature solution interpolation mode");
00376 
00377     startwavelength = dfs_get_parameter_double(parlist, 
00378                     "fors.vimos_calib.startwavelength", grism_table);
00379     if (startwavelength > 1.0)
00380         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00381             vimos_calib_exit("Invalid wavelength");
00382 
00383     endwavelength = dfs_get_parameter_double(parlist, 
00384                     "fors.vimos_calib.endwavelength", grism_table);
00385     if (endwavelength > 1.0) {
00386         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00387             vimos_calib_exit("Invalid wavelength");
00388         if (startwavelength < 1.0)
00389             vimos_calib_exit("Invalid wavelength interval");
00390     }
00391 
00392     if (startwavelength > 1.0)
00393         if (endwavelength - startwavelength <= 0.0)
00394             vimos_calib_exit("Invalid wavelength interval");
00395 
00396     reference = dfs_get_parameter_double(parlist,
00397                 "fors.vimos_calib.reference", grism_table);
00398 
00399     if (reference < startwavelength || reference > endwavelength)
00400         vimos_calib_exit("Invalid reference wavelength");
00401 
00402     slit_ident = dfs_get_parameter_bool(parlist, 
00403                     "fors.vimos_calib.slit_ident", NULL);
00404 
00405     sdegree = dfs_get_parameter_int(parlist, "fors.vimos_calib.sdegree", NULL);
00406     ddegree = dfs_get_parameter_int(parlist, "fors.vimos_calib.ddegree", NULL);
00407     sradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.sradius", NULL);
00408     dradius = dfs_get_parameter_int(parlist, "fors.vimos_calib.dradius", NULL);
00409 
00410     if (sradius < 1 || dradius < 1)
00411         vimos_calib_exit("Invalid smoothing box radius");
00412 
00413     qc = dfs_get_parameter_bool(parlist, "fors.vimos_calib.qc", NULL);
00414 
00415     check = dfs_get_parameter_bool(parlist, "fors.vimos_calib.check", NULL);
00416 
00417     cpl_table_delete(grism_table); grism_table = NULL;
00418 
00419     if (cpl_error_get_code())
00420         vimos_calib_exit("Failure getting the configuration parameters");
00421 
00422 
00423     /* 
00424      * Check input set-of-frames
00425      */
00426 
00427     cpl_msg_indent_less();
00428     cpl_msg_info(recipe, "Check input set-of-frames:");
00429     cpl_msg_indent_more();
00430 
00431     if (!dfs_equal_keyword(frameset, "ESO OCS CON QUAD")) 
00432         vimos_calib_exit("Input frames are not from the same quadrant");
00433 
00434     mos = cpl_frameset_count_tags(frameset, "MOS_ARC_SPECTRUM");
00435 
00436     if (mos == 0)
00437         vimos_calib_exit("Missing input arc lamp frame");
00438 
00439     if (mos > 1)
00440         vimos_calib_exit("Just one input arc lamp frame is allowed"); 
00441 
00442     arc_tag                  = "MOS_ARC_SPECTRUM";
00443     flat_tag                 = "MOS_SCREEN_FLAT";
00444     master_screen_flat_tag   = "MOS_COMBINED_SCREEN_FLAT";
00445     master_norm_flat_tag     = "MOS_MASTER_SCREEN_FLAT";
00446     reduced_lamp_tag         = "MOS_ARC_SPECTRUM_EXTRACTED";
00447     disp_residuals_tag       = "MOS_DISP_RESIDUALS";
00448     disp_coeff_tag           = "MOS_DISP_COEFF";
00449     wavelength_map_tag       = "MOS_WAVELENGTH_MAP";
00450     spectra_detection_tag    = "MOS_SPECTRA_DETECTION";
00451     spectral_resolution_tag  = "MOS_SPECTRAL_RESOLUTION";
00452     slit_map_tag             = "MOS_SLIT_MAP";
00453     curv_traces_tag          = "MOS_CURV_TRACES";
00454     curv_coeff_tag           = "MOS_CURV_COEFF";
00455     spatial_map_tag          = "MOS_SPATIAL_MAP";
00456     slit_location_tag        = "MOS_SLIT_LOCATION";
00457     disp_residuals_table_tag = "MOS_DISP_RESIDUALS_TABLE";
00458     delta_image_tag          = "MOS_DELTA_IMAGE";
00459 
00460     nbias = 0;
00461     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) {
00462         if (cpl_frameset_count_tags(frameset, "BIAS") == 0)
00463             vimos_calib_exit("Missing required input: MASTER_BIAS or BIAS");
00464         nbias = cpl_frameset_count_tags(frameset, "BIAS");
00465     }
00466 
00467     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00468         vimos_calib_exit("Too many in input: MASTER_BIAS");
00469 
00470     if (cpl_frameset_count_tags(frameset, "LINE_CATALOG") == 0)
00471         vimos_calib_exit("Missing required input: LINE_CATALOG");
00472 
00473     if (cpl_frameset_count_tags(frameset, "LINE_CATALOG") > 1)
00474         vimos_calib_exit("Too many in input: LINE_CATALOG");
00475 
00476     nflats = cpl_frameset_count_tags(frameset, flat_tag);
00477 
00478     if (nflats < 1) {
00479         cpl_msg_error(recipe, "Missing required input: %s", flat_tag);
00480         vimos_calib_exit(NULL);
00481     }
00482 
00483     cpl_msg_indent_less();
00484 
00485     if (nflats > 1)
00486         cpl_msg_info(recipe, "Load %d flat field frames and sum them...",
00487                      nflats);
00488     else
00489         cpl_msg_info(recipe, "Load flat field exposure...");
00490 
00491     cpl_msg_indent_more();
00492 
00493     header = dfs_load_header(frameset, flat_tag, 0);
00494 
00495     if (header == NULL)
00496         vimos_calib_exit("Cannot load flat field frame header");
00497 
00498     alltime = cpl_propertylist_get_double(header, "EXPTIME");
00499 
00500     if (cpl_error_get_code() != CPL_ERROR_NONE)
00501         vimos_calib_exit("Missing keyword EXPTIME in flat field frame header");
00502 
00503     cpl_propertylist_delete(header);
00504 
00505     for (i = 1; i < nflats; i++) {
00506 
00507         header = dfs_load_header(frameset, NULL, 0);
00508 
00509         if (header == NULL)
00510             vimos_calib_exit("Cannot load flat field frame header");
00511 
00512         alltime += cpl_propertylist_get_double(header, "EXPTIME");
00513 
00514         if (cpl_error_get_code() != CPL_ERROR_NONE)
00515             vimos_calib_exit("Missing keyword EXPTIME in flat field "
00516                             "frame header");
00517 
00518         cpl_propertylist_delete(header);
00519 
00520     }
00521 
00522     master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0);
00523 
00524     if (master_flat == NULL)
00525         vimos_calib_exit("Cannot load flat field");
00526 
00527     for (i = 1; i < nflats; i++) {
00528         flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
00529         if (flat) {
00530             cpl_image_add(master_flat, flat);
00531             cpl_image_delete(flat); flat = NULL;
00532         }
00533         else
00534             vimos_calib_exit("Cannot load flat field");
00535     }
00536 
00537 
00538     /*
00539      * Get some info from arc lamp header
00540      */
00541 
00542     header = dfs_load_header(frameset, arc_tag, 0);
00543 
00544     if (header == NULL)
00545         vimos_calib_exit("Cannot load arc lamp header");
00546 
00547     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00548     if (instrume == NULL)
00549         vimos_calib_exit("Missing keyword INSTRUME in arc lamp header");
00550     instrume = cpl_strdup(instrume);
00551 
00552     arctime = cpl_propertylist_get_double(header, "EXPTIME");
00553 
00554     quadrant = cpl_propertylist_get_int(header, "ESO OCS CON QUAD");
00555 
00556     switch (quadrant) {
00557     case 1:
00558         key_gris_name = "ESO INS GRIS1 NAME";
00559         key_gris_id = "ESO INS GRIS1 ID";
00560         key_filt_name = "ESO INS FILT1 NAME";
00561         key_filt_id = "ESO INS FILT1 ID";
00562         key_mask_id = "ESO INS MASK1 ID";
00563         break;
00564     case 2:
00565         key_gris_name = "ESO INS GRIS2 NAME";
00566         key_gris_id = "ESO INS GRIS2 ID";
00567         key_filt_name = "ESO INS FILT2 NAME";
00568         key_filt_id = "ESO INS FILT2 ID";
00569         key_mask_id = "ESO INS MASK2 ID";
00570         break;
00571     case 3:
00572         key_gris_name = "ESO INS GRIS3 NAME";
00573         key_gris_id = "ESO INS GRIS3 ID";
00574         key_filt_name = "ESO INS FILT3 NAME";
00575         key_filt_id = "ESO INS FILT3 ID";
00576         key_mask_id = "ESO INS MASK3 ID";
00577         break;
00578     case 4:
00579         key_gris_name = "ESO INS GRIS4 NAME";
00580         key_gris_id = "ESO INS GRIS4 ID";
00581         key_filt_name = "ESO INS FILT4 NAME";
00582         key_filt_id = "ESO INS FILT4 ID";
00583         key_mask_id = "ESO INS MASK4 ID";
00584         break;
00585     }
00586 
00587     grism = cpl_strdup(cpl_propertylist_get_string(header, key_gris_name));
00588 
00589     if (cpl_error_get_code() != CPL_ERROR_NONE)
00590         vimos_calib_exit("Missing keyword ESO INS GRISn NAME in arc lamp "
00591                          "frame header");
00592 
00593     cpl_msg_info(recipe, "The grism is: %s", grism);
00594 
00595 /*
00596     if (!dfs_equal_keyword(frameset, key_gris_id))
00597         vimos_calib_exit("Input frames are not from the same grism");
00598 
00599     if (!dfs_equal_keyword(frameset, key_filt_id))
00600         vimos_calib_exit("Input frames are not from the same filter");
00601 */
00602 
00603     gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
00604 
00605     if (cpl_error_get_code() != CPL_ERROR_NONE)
00606         vimos_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp "
00607                         "frame header");
00608 
00609     cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
00610 
00611     cpl_msg_info(recipe, "Produce mask slit position table...");
00612 
00613     maskslits = mos_load_slits_vimos(header);
00614 
00615     /*
00616      * Check if all slits have the same X offset: in such case, 
00617      * treat the observation as a long-slit one!
00618      */
00619 
00620     mxpos = cpl_table_get_column_median(maskslits, "ytop");
00621     xpos = cpl_table_get_data_double(maskslits, "ytop");
00622     nslits = cpl_table_get_nrow(maskslits);
00623 
00624     treat_as_lss = 1;
00625     for (i = 0; i < nslits; i++) {
00626         if (fabs(mxpos-xpos[i]) > 0.01) {
00627             treat_as_lss = 0;
00628             break;
00629         }
00630     }
00631 
00632     if (treat_as_lss) {
00633         cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n"
00634                         "The long-slit data reduction strategy is applied!", 
00635                         mxpos);
00636         cpl_table_delete(maskslits); maskslits = NULL;
00637     }
00638 
00639     if (slit_ident == 0) {
00640         cpl_table_delete(maskslits); maskslits = NULL;
00641     }
00642 
00643 
00644     /* Leave the header on for the next step... */
00645 
00646 
00647     /*
00648      * Remove the master bias
00649      */
00650 
00651     if (nbias) {
00652 
00653         /*
00654          * Set of raw BIASes in input, need to create master bias!
00655          */
00656 
00657         cpl_msg_info(recipe, "Generate the master from input raw biases...");
00658 
00659         if (nbias > 1) {
00660 
00661             biases = cpl_imagelist_new();
00662 
00663             bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0);
00664     
00665             if (bias == NULL)
00666                 vimos_calib_exit("Cannot load bias frame");
00667 
00668             cpl_imagelist_set(biases, bias, 0); bias = NULL;
00669     
00670             for (i = 1; i < nbias; i++) {
00671                 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
00672                 if (bias) {
00673                     cpl_imagelist_set(biases, bias, i); bias = NULL;
00674                 }
00675                 else
00676                     vimos_calib_exit("Cannot load bias frame");
00677             }
00678     
00679             master_bias = cpl_imagelist_collapse_median_create(biases);
00680 
00681             cpl_imagelist_delete(biases);
00682         }
00683         else
00684             master_bias = dfs_load_image(frameset, "BIAS", 
00685                                          CPL_TYPE_FLOAT, 0, 1);
00686 
00687     }
00688     else {
00689         master_bias = dfs_load_image(frameset, "MASTER_BIAS", 
00690                                      CPL_TYPE_FLOAT, 0, 1);
00691         if (master_bias == NULL)
00692             vimos_calib_exit("Cannot load master bias");
00693     }
00694 
00695     cpl_msg_info(recipe, "Remove the master bias...");
00696 
00697     overscans = mos_load_overscans_vimos(header, 1);
00698     cpl_propertylist_delete(header); header = NULL;
00699 
00700     if (nbias) {
00701         int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
00702         int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
00703         int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
00704         int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
00705         dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig);
00706         cpl_image_delete(master_bias); master_bias = dummy;
00707 
00708         if (dfs_save_image(frameset, master_bias, "MASTER_BIAS",
00709                            NULL, parlist, recipe, version))
00710             vimos_calib_exit(NULL);
00711     }
00712 
00713     if (nflats > 1) {
00714         multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats);
00715         dummy = mos_remove_bias(master_flat, multi_bias, overscans);
00716         cpl_image_delete(multi_bias);
00717     }
00718     else {
00719         dummy = mos_remove_bias(master_flat, master_bias, overscans);
00720     }
00721     cpl_image_delete(master_flat);
00722     master_flat = dummy;
00723 
00724     if (master_flat == NULL)
00725         vimos_calib_exit("Cannot remove bias from flat field");
00726 
00727     cpl_msg_indent_less();
00728     cpl_msg_info(recipe, "Load arc lamp exposure...");
00729     cpl_msg_indent_more();
00730 
00731     spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00732 
00733     if (spectra == NULL)
00734         vimos_calib_exit("Cannot load arc lamp exposure");
00735 
00736     cpl_msg_info(recipe, "Remove the master bias...");
00737 
00738     dummy = mos_remove_bias(spectra, master_bias, overscans);
00739     cpl_table_delete(overscans); overscans = NULL;
00740     cpl_image_delete(master_bias); master_bias = NULL;
00741     cpl_image_delete(spectra); spectra = dummy;
00742 
00743     if (spectra == NULL)
00744         vimos_calib_exit("Cannot remove bias from arc lamp exposure");
00745 
00746     cpl_msg_indent_less();
00747     cpl_msg_info(recipe, "Load input line catalog...");
00748     cpl_msg_indent_more();
00749 
00750     wavelengths = dfs_load_table(frameset, "LINE_CATALOG", 1);
00751 
00752     if (wavelengths == NULL)
00753         vimos_calib_exit("Cannot load line catalog");
00754 
00755 
00756     /*
00757      * Cast the wavelengths into a (double precision) CPL vector
00758      */
00759 
00760     nlines = cpl_table_get_nrow(wavelengths);
00761 
00762     if (nlines == 0)
00763         vimos_calib_exit("Empty input line catalog");
00764 
00765     if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00766         cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00767                       wcolumn);
00768         vimos_calib_exit(NULL);
00769     }
00770 
00771     line = cpl_malloc(nlines * sizeof(double));
00772     
00773     for (i = 0; i < nlines; i++)
00774         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00775 
00776     cpl_table_delete(wavelengths); wavelengths = NULL;
00777 
00778     lines = cpl_vector_wrap(nlines, line);
00779 
00780 
00781     /*
00782      * Rotate frames horizontally with red to the right
00783      */
00784 
00785     cpl_image_turn(spectra, rotate);
00786     cpl_image_turn(master_flat, rotate);
00787 
00788     ccd_xsize = nx = cpl_image_get_size_x(spectra);      // added...
00789     ccd_ysize = ny = cpl_image_get_size_y(spectra);
00790 
00791     if (treat_as_lss) {
00792 
00793         /*
00794          * In the case of LSS data, find first a "one slit"
00795          * solution. This will be later on split into many-slits
00796          * solutions. This is done for greater accuracy.
00797          */
00798 
00799         cpl_msg_indent_less();
00800         cpl_msg_info(recipe, "Perform wavelength calibration...");
00801         cpl_msg_indent_more();
00802 
00803         wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00804         if (check)
00805             residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00806 
00807         fiterror = cpl_calloc(ny, sizeof(double));
00808         fitlines = cpl_calloc(ny, sizeof(int));
00809         idscoeff = cpl_table_new(ny);
00810         refmask  = cpl_mask_new(nx, ny);
00811 
00812     if (mos_saturation_process(spectra))
00813         vimos_calib_exit("Cannot process saturation");
00814 
00815     if (mos_subtract_background(spectra))
00816         vimos_calib_exit("Cannot subtract the background");
00817 
00818         rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion,
00819                                                    peakdetection, wradius,
00820                                                    wdegree, wreject, reference,
00821                                                    &startwavelength, 
00822                                                    &endwavelength, fitlines, 
00823                                                    fiterror, idscoeff, wavemap,
00824                                                    residual, NULL, refmask);
00825 
00826         if (rectified == NULL)
00827             vimos_calib_exit("Wavelength calibration failure.");
00828 
00829         if (!cpl_table_has_valid(idscoeff, "c0"))
00830             vimos_calib_exit("Wavelength calibration failure.");
00831 
00832         /*
00833          * This is necessary to move on to a many-slits solution
00834          */
00835 
00836         mos_refmask_find_gaps(refmask, master_flat, 1000.);
00837 
00838         if (wmode) {
00839             cpl_image_delete(rectified); rectified = NULL;
00840             cpl_image_delete(wavemap); wavemap = NULL;
00841             mos_interpolate_wavecalib(idscoeff, wavemap, wmode);
00842             wavemap = mos_map_idscoeff(idscoeff, nx, reference,
00843                                        startwavelength, endwavelength);
00844             rectified = mos_wavelength_calibration(spectra, reference,
00845                                                    startwavelength, 
00846                                                    endwavelength, dispersion, 
00847                                                    idscoeff, 0);
00848         }
00849 
00850         cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
00851         cpl_table_set_column_unit(idscoeff, "error", "pixel");
00852         cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
00853 
00854         for (i = 0; i < ny; i++)
00855             if (!cpl_table_is_valid(idscoeff, "c0", i))
00856                 cpl_table_set_invalid(idscoeff, "error", i);
00857 
00858         slit_ident = 0;
00859         idscoeff_lss = idscoeff;
00860 
00861     }
00862     else {
00863 
00864         /*
00865          * Here the generic MOS calibration is carried out.
00866          */
00867 
00868         /*
00869          * Detecting spectra on the CCD
00870          */
00871 
00872         cpl_msg_indent_less();
00873         cpl_msg_info(recipe, "Detecting spectra on CCD...");
00874         cpl_msg_indent_more();
00875 
00876         ccd_xsize = nx = cpl_image_get_size_x(spectra);
00877         ccd_ysize = ny = cpl_image_get_size_y(spectra);
00878 
00879         refmask = cpl_mask_new(nx, ny);
00880 
00881         if (mos_saturation_process(spectra))
00882         vimos_calib_exit("Cannot process saturation");
00883 
00884         if (mos_subtract_background(spectra))
00885         vimos_calib_exit("Cannot subtract the background");
00886 
00887         checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion, 
00888                                                    peakdetection, wradius, 
00889                                                    wdegree, wreject, reference,
00890                                                    &startwavelength, 
00891                                                    &endwavelength,
00892                                                    NULL, NULL, NULL, NULL, 
00893                                                    NULL, NULL, refmask);
00894 
00895         if (checkwave == NULL)
00896             vimos_calib_exit("Wavelength calibration failure.");
00897 
00898         /*
00899          * Save check image to disk
00900          */
00901 
00902         header = cpl_propertylist_new();
00903         cpl_propertylist_update_double(header, "CRPIX1", 1.0);
00904         cpl_propertylist_update_double(header, "CRPIX2", 1.0);
00905         cpl_propertylist_update_double(header, "CRVAL1", 
00906                                        startwavelength + dispersion/2);
00907         cpl_propertylist_update_double(header, "CRVAL2", 1.0);
00908         /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
00909         cpl_propertylist_update_double(header, "CDELT2", 1.0); */
00910         cpl_propertylist_update_double(header, "CD1_1", dispersion);
00911         cpl_propertylist_update_double(header, "CD1_2", 0.0);
00912         cpl_propertylist_update_double(header, "CD2_1", 0.0);
00913         cpl_propertylist_update_double(header, "CD2_2", 1.0);
00914         cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
00915         cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
00916 
00917         if (check) {
00918             if (dfs_save_image(frameset, checkwave, spectra_detection_tag, 
00919                                header, parlist, recipe, version))
00920                 vimos_calib_exit(NULL);
00921         }
00922 
00923         cpl_image_delete(checkwave); checkwave = NULL;
00924         cpl_propertylist_delete(header); header = NULL;
00925 
00926     }
00927 
00928     cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD...");
00929     slits = mos_locate_spectra(refmask);
00930 
00931     if (!slits) {
00932         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
00933         vimos_calib_exit("No slits could be detected!");
00934     }
00935 
00936     refimage = cpl_image_new_from_mask(refmask);
00937     cpl_mask_delete(refmask); refmask = NULL;
00938 
00939     if (check) {
00940         save_header = dfs_load_header(frameset, arc_tag, 0);
00941         cpl_image_turn(refimage, rotate_back);
00942         if (dfs_save_image(frameset, refimage, slit_map_tag, NULL,
00943                            parlist, recipe, version))
00944             vimos_calib_exit(NULL);
00945         cpl_propertylist_delete(save_header); save_header = NULL;
00946     }
00947 
00948     cpl_image_delete(refimage); refimage = NULL;
00949 
00950     if (slit_ident) {
00951 
00952         /*
00953          * Attempt slit identification: this recipe may continue even
00954          * in case of failed identification (i.e., the position table is 
00955          * not produced, but an error is not set). In case of failure,
00956          * the spectra would be still extracted, even if they would not
00957          * be associated to slits on the mask.
00958          * 
00959          * The reason for making the slit identification an user option 
00960          * (via the parameter slit_ident) is to offer the possibility 
00961          * to avoid identifications that are only apparently successful, 
00962          * as it would happen in the case of an incorrect slit description 
00963          * in the data header.
00964          */
00965 
00966         cpl_msg_indent_less();
00967         cpl_msg_info(recipe, "Attempt slit identification (optional)...");
00968         cpl_msg_indent_more();
00969 
00970         mos_rotate_slits(maskslits, -rotate, 0, 0);
00971         positions = mos_identify_slits(slits, maskslits, NULL);
00972 
00973         if (positions) {
00974             cpl_table_delete(slits);
00975             slits = positions;
00976 
00977             /*
00978              * Eliminate slits which are _entirely_ outside the CCD
00979              */
00980 
00981             cpl_table_and_selected_double(slits, 
00982                                           "ybottom", CPL_GREATER_THAN, ny-1);
00983             cpl_table_or_selected_double(slits, 
00984                                           "ytop", CPL_LESS_THAN, 0);
00985             cpl_table_erase_selected(slits);
00986 
00987             nslits = cpl_table_get_nrow(slits);
00988 
00989             if (nslits == 0)
00990                 vimos_calib_exit("No slits found on the CCD");
00991 
00992             cpl_msg_info(recipe, "%d slits are entirely or partially "
00993                          "contained in CCD", nslits);
00994 
00995         }
00996         else {
00997             slit_ident = 0;
00998             cpl_msg_info(recipe, "Global distortion model cannot be computed");
00999             if (cpl_error_get_code() != CPL_ERROR_NONE) {
01000                 vimos_calib_exit(NULL);
01001             }
01002         }
01003     }
01004 
01005 
01006     /*
01007      * Determination of spectral curvature
01008      */
01009 
01010     cpl_msg_indent_less();
01011     cpl_msg_info(recipe, "Determining spectral curvature...");
01012     cpl_msg_indent_more();
01013 
01014     cpl_msg_info(recipe, "Tracing master flat field spectra edges...");
01015     traces = mos_trace_flat(master_flat, slits, reference, 
01016                             startwavelength, endwavelength, dispersion);
01017 
01018     if (!traces)
01019         vimos_calib_exit("Tracing failure");
01020 
01021     cpl_msg_info(recipe, "Fitting flat field spectra edges...");
01022     polytraces = mos_poly_trace(slits, traces, cdegree);
01023 
01024     if (!polytraces)
01025         vimos_calib_exit("Trace fitting failure");
01026 
01027     if (cmode) {
01028         cpl_msg_info(recipe, "Computing global spectral curvature model...");
01029         mos_global_trace(slits, polytraces, cmode);
01030     }
01031 
01032     if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist,
01033                        recipe, version))
01034         vimos_calib_exit(NULL);
01035 
01036     cpl_table_delete(traces); traces = NULL;
01037 
01038     coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01039     spatial = mos_spatial_calibration(spectra, slits, polytraces, reference, 
01040                                       startwavelength, endwavelength, 
01041                                       dispersion, 0, coordinate);
01042 
01043 //    if (!slit_ident) {
01044 //        cpl_image_delete(spectra); spectra = NULL;
01045 //    }
01046 
01047     /*
01048      * Flat field normalisation is done directly on the master flat
01049      * field (without spatial rectification first). The spectral
01050      * curvature model may be provided in input, in future releases.
01051      */
01052 
01053     cpl_msg_indent_less();
01054     cpl_msg_info(recipe, "Perform flat field normalisation...");
01055     cpl_msg_indent_more();
01056 
01057     norm_flat = cpl_image_duplicate(master_flat);
01058 
01059     smo_flat = mos_normalise_flat(norm_flat, coordinate, slits, polytraces, 
01060                                   reference, startwavelength, endwavelength,
01061                                   dispersion, dradius, ddegree);
01062 
01063     cpl_image_delete(smo_flat); smo_flat = NULL;  /* It may be a product */
01064  
01065     save_header = dfs_load_header(frameset, flat_tag, 0);
01066     cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats);
01067 
01068     cpl_image_turn(norm_flat, rotate_back);
01069 
01070     if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag,
01071                        save_header, parlist, recipe, version))
01072         vimos_calib_exit(NULL);
01073 
01074     cpl_image_delete(norm_flat); norm_flat = NULL;
01075 
01076 
01077     /*
01078      * QC parameters for flat
01079      */
01080 
01081     if (qc) {
01082         double     scale;
01083         double     slit_width;
01084         double     flux, flux_err;
01085         int        cslit = mos_slit_closest_to_center(slits, nx, ny);
01086 
01087 
01088         /*
01089          * Refresh base property list, because previous saving 
01090          * modified it - e.g., the keyword ARCFILE is missing
01091          */
01092 
01093         cpl_propertylist_delete(save_header);
01094         save_header = dfs_load_header(frameset, flat_tag, 0);
01095         cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats);
01096 
01097 
01098         /*
01099          * QC1 group header
01100          */
01101 
01102         fors_qc_start_group(save_header, "1.1", instrume);
01103 
01104         if (fors_qc_write_string("PRO.CATG", master_norm_flat_tag,
01105                                  "Product category", instrume))
01106             vimos_calib_exit("Cannot write product category to QC log file");
01107 
01108         if (fors_qc_keyword_to_paf(save_header, "ARCFILE", NULL,
01109                                    "Archive File Name", instrume))
01110             vimos_calib_exit("Missing keyword ARCFILE in flatfield frame");
01111 
01112         if (fors_qc_keyword_to_paf(save_header, "ESO TPL ID", NULL,
01113                                    "Template signature ID", instrume))
01114             vimos_calib_exit("Missing keyword TPL ID in flatfield frame");
01115 
01116         if (fors_qc_keyword_to_paf(save_header, "ESO OCS CON QUAD", NULL,
01117                                    "Quadrant", instrume))
01118             vimos_calib_exit("Missing keyword OCS CON QUAD in flatfield frame");
01119 
01120         if (fors_qc_keyword_to_paf(save_header, key_filt_name, NULL,
01121                                    "Filter", instrume)) {
01122             cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 
01123                           key_filt_name);
01124             vimos_calib_exit(NULL);
01125         }
01126 
01127         if (fors_qc_keyword_to_paf(save_header, key_gris_name, NULL,
01128                                    "Grism", instrume)) {
01129             cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 
01130                           key_gris_name);
01131             vimos_calib_exit(NULL);
01132         }
01133 
01134         if (fors_qc_keyword_to_paf(save_header, key_mask_id, NULL,
01135                                    "Mask", instrume)) {
01136             cpl_msg_error(recipe, "Missing keyword %s in flatfield frame", 
01137                           key_mask_id);
01138             vimos_calib_exit(NULL);
01139         }
01140 
01141         cpl_propertylist_update_double(save_header, 
01142                                        "ESO PRO WLEN CEN", reference);
01143 
01144         if (fors_qc_keyword_to_paf(save_header, "ESO PRO WLEN CEN", "Angstrom",
01145                                    "Reference wavelength", instrume))
01146             vimos_calib_exit("Missing keyword PRO WLEN CEN in flatfield frame");
01147 
01148 /* Unused in the old VIMOS pipeline:
01149 
01150         if (fors_qc_keyword_to_paf(save_header, "ESO DPR TYPE", NULL,
01151                                    "DPR type", instrume))
01152             vimos_calib_exit("Missing keyword DPR TYPE in flat field frame");
01153 
01154         if (fors_qc_keyword_to_paf(save_header, key_gris_id, NULL,
01155                                   "Grism identifier", instrume)) {
01156             cpl_msg_error(recipe, "Missing keyword %s in arc "
01157                             "lamp header", key_gris_id);
01158             vimos_calib_exit(NULL);
01159         }
01160 
01161         if (cpl_propertylist_has(save_header, key_filt_name))
01162             fors_qc_keyword_to_paf(save_header, key_filt_name, NULL,
01163                                   "Filter name", instrume);
01164 
01165         if (fors_qc_keyword_to_paf(save_header, "ESO DET CHIP1 ID", NULL,
01166                                   "Chip identifier", instrume))
01167             vimos_calib_exit("Missing keyword DET CHIP1 ID in arc "
01168                             "lamp header");
01169 */
01170 
01171         pipefile = dfs_generate_filename_tfits(master_norm_flat_tag);
01172         if (fors_qc_write_string("PIPEFILE", pipefile,
01173                                 "Pipeline product name", instrume))
01174             vimos_calib_exit("Cannot write PIPEFILE to QC log file");
01175         cpl_free(pipefile); pipefile = NULL;
01176 
01177         scale = cpl_propertylist_get_double(save_header, "ESO TEL FOCU SCALE");
01178 
01179         if (cpl_error_get_code()) {
01180             cpl_error_reset();
01181             scale = 1.718;
01182             cpl_msg_warning(recipe, "Cannot read keyword TEL FOCU SCALE "
01183                             "(defaulted to %f arcsec/mm)", scale);
01184         }
01185 
01186         /*
01187          * QC1 parameters
01188          */
01189 
01190         keyname = "QC.MOS.SLIT.WIDTH";
01191 
01192         slit_width = scale * cpl_table_get(slits, "ywidth", cslit, NULL);
01193 
01194         if (fors_qc_write_qc_double(save_header, slit_width, keyname, "arcsec",
01195                                     "Width of slit closest to center",
01196                                     instrume)) {
01197             vimos_calib_exit("Cannot write slit width to QC log file");
01198         }
01199 
01200         mos_extract_flux(master_flat, slits, 2, gain, &flux, &flux_err);
01201 
01202         flux_err /= alltime; // The master is simply the sum of all flats
01203         flux     /= alltime;
01204 
01205         cpl_msg_info(recipe, 
01206                      "Flux at wavelength %.2f: %.2f +/- %.2f ADU/mm^2/s\n",
01207                      reference, flux, flux_err);
01208 
01209         keyname = "QC.MOS.FLAT.FLUX";
01210 
01211         if (fors_qc_write_qc_double(save_header, flux, keyname, "ADU/mm^2/s",
01212                                     "Flux at reference wavelength",
01213                                     instrume)) {
01214             vimos_calib_exit("Cannot write QC.MOS.FLAT.FLUX to QC log file");
01215         }
01216 
01217         keyname = "QC.MOS.FLAT.FLUXERR";
01218 
01219         if (fors_qc_write_qc_double(save_header, flux_err, keyname, 
01220                                     "ADU/mm^2/s",
01221                                     "Error on flux at reference wavelength",
01222                                     instrume)) {
01223             vimos_calib_exit("Cannot write QC.MOS.FLAT.FLUXERR to QC log file");
01224         }
01225 
01226         fors_qc_end_group();
01227 
01228     }
01229 
01230     cpl_image_turn(master_flat, rotate_back);
01231     if (dfs_save_image(frameset, master_flat, master_screen_flat_tag,
01232                        save_header, parlist, recipe, version))
01233         vimos_calib_exit(NULL);
01234 
01235     cpl_image_delete(master_flat); master_flat = NULL;
01236 
01237     cpl_propertylist_delete(save_header); save_header = NULL;
01238 
01239 
01240     /*
01241      * Final wavelength calibration of spectra having their curvature
01242      * removed
01243      */
01244 
01245     cpl_msg_indent_less();
01246     cpl_msg_info(recipe, "Perform final wavelength calibration...");
01247     cpl_msg_indent_more();
01248 
01249     nx = cpl_image_get_size_x(spatial);
01250     ny = cpl_image_get_size_y(spatial);
01251 
01252     idscoeff = cpl_table_new(ny);
01253     restable = cpl_table_new(nlines);
01254     rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01255     if (check)
01256         residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01257     fiterror = cpl_calloc(ny, sizeof(double));
01258     fitlines = cpl_calloc(ny, sizeof(int));
01259 
01260     rectified = mos_wavelength_calibration_final(spatial, slits, lines, 
01261                                                  dispersion, peakdetection, 
01262                                                  wradius, wdegree, wreject,
01263                                                  reference, &startwavelength, 
01264                                                  &endwavelength, fitlines, 
01265                                                  fiterror, idscoeff, rainbow, 
01266                                                  residual, restable);
01267 
01268     if (rectified == NULL)
01269         vimos_calib_exit("Wavelength calibration failure.");
01270 
01271     if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL,
01272                        parlist, recipe, version))
01273         vimos_calib_exit(NULL);
01274 
01275     cpl_table_delete(restable); restable = NULL;
01276 
01277     cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
01278     cpl_table_set_column_unit(idscoeff, "error", "pixel");
01279     cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
01280 
01281     if (treat_as_lss) {
01282 
01283         const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01284 
01285         int    *position = cpl_table_get_data_int   (slits, "position");
01286         int    *length   = cpl_table_get_data_int   (slits, "length");
01287         double *ytop     = cpl_table_get_data_double(slits, "ytop");
01288         double *ybottom  = cpl_table_get_data_double(slits, "ybottom");
01289 
01290         int     j, k, dr, irow;
01291 
01292         /*
01293          * Replace the LSS solutions to the poorer MOS solutions
01294          */
01295 
01296         for (j = 0, i = ny - 1; i >= 0; i--) {
01297             if (i < position[j]) {
01298                 ++j;
01299             }
01300             dr = position[j] + length[j] - i - 1;
01301             irow = floor(ytop[j] - dr*(ytop[j] - ybottom[j])/length[j] + 0.5);
01302             for (k = 0; k <= wdegree; k++) {
01303                 cpl_table_set_double(idscoeff, clab[k], i, 
01304                 cpl_table_get_double(idscoeff_lss, clab[k], irow, NULL));
01305             }
01306             cpl_table_set_double(idscoeff, "error", i,
01307             cpl_table_get_double(idscoeff_lss, "error", irow, NULL));
01308             cpl_table_set_int(idscoeff, "nlines", i,
01309             cpl_table_get_int(idscoeff_lss, "nlines", irow, NULL));
01310         }
01311 
01312         cpl_table_delete(idscoeff_lss);
01313 
01314         cpl_image_delete(rectified);
01315 
01316         rectified = mos_wavelength_calibration(spatial, reference,
01317                                                startwavelength, endwavelength,
01318                                                dispersion, idscoeff, 0);
01319     }
01320     else {
01321         for (i = 0; i < ny; i++)
01322             if (!cpl_table_is_valid(idscoeff, "c0", i))
01323                 cpl_table_set_invalid(idscoeff, "error", i);
01324     }
01325 
01326     cpl_image_delete(spatial); spatial = NULL;
01327 
01328     delta = mos_map_pixel(idscoeff, reference, startwavelength,
01329                           endwavelength, dispersion, 2);
01330 
01331     header = cpl_propertylist_new();
01332     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01333     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01334     cpl_propertylist_update_double(header, "CRVAL1",
01335                                    startwavelength + dispersion/2);
01336     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01337     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01338     cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01339     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01340     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01341     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01342     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01343     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01344     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01345 
01346     if (dfs_save_image(frameset, delta, delta_image_tag,
01347                        header, parlist, recipe, version))
01348         vimos_calib_exit(NULL);
01349 
01350     cpl_image_delete(delta); delta = NULL;
01351     cpl_propertylist_delete(header); header = NULL;
01352 
01353     mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 
01354                                    dispersion, 6, 0);
01355 
01356     cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
01357 
01358     mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01359 
01360     cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 
01361                  mean_rms, mean_rms * dispersion);
01362 
01363     restab = mos_resolution_table(rectified, startwavelength, dispersion, 
01364                                   60000, lines);
01365 
01366     if (restab) {
01367         cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 
01368                    cpl_table_get_column_mean(restab, "resolution"));
01369         cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel",
01370                    cpl_table_get_column_mean(restab, "fwhm") / dispersion,
01371                    cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
01372 
01373         if (qc) {
01374 
01375             header = dfs_load_header(frameset, arc_tag, 0);
01376 
01377             if (header == NULL)
01378                 vimos_calib_exit("Cannot reload arc lamp header");
01379 
01380             qclist = cpl_propertylist_new();
01381 
01382             fors_qc_start_group(qclist, "1.1", instrume);
01383 
01384 
01385             /*
01386              * QC1 group header
01387              */
01388 
01389             if (fors_qc_write_string("PRO.CATG", spectral_resolution_tag,
01390                                     "Product category", instrume))
01391                 vimos_calib_exit("Cannot write product category to "
01392                                 "QC log file");
01393 
01394             if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
01395                                       "DPR type", instrume))
01396                 vimos_calib_exit("Missing keyword DPR TYPE in arc "
01397                                 "lamp header");
01398 
01399             if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
01400                                       "Template", instrume))
01401                 vimos_calib_exit("Missing keyword TPL ID in arc "
01402                                 "lamp header");
01403 
01404             if (fors_qc_keyword_to_paf(header, key_gris_name, NULL,
01405                                       "Grism name", instrume)) {
01406                 cpl_msg_error(recipe, "Missing keyword %s in arc "
01407                                 "lamp header", key_gris_name);
01408                 vimos_calib_exit(NULL);
01409             }
01410 
01411             if (fors_qc_keyword_to_paf(header, key_gris_id, NULL,
01412                                       "Grism identifier", instrume)) {
01413                 cpl_msg_error(recipe, "Missing keyword %s in arc "
01414                                 "lamp header", key_gris_id);
01415                 vimos_calib_exit(NULL);
01416             }
01417 
01418             if (cpl_propertylist_has(header, key_filt_name))
01419                 fors_qc_keyword_to_paf(header, key_filt_name, NULL,
01420                                       "Filter name", instrume);
01421 
01422             if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
01423                                       "Chip identifier", instrume))
01424                 vimos_calib_exit("Missing keyword DET CHIP1 ID in arc "
01425                                 "lamp header");
01426 
01427             if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
01428                                       "Archive name of input data", 
01429                                       instrume))
01430                 vimos_calib_exit("Missing keyword ARCFILE in arc "
01431                                 "lamp header");
01432 
01433             cpl_propertylist_delete(header); header = NULL;
01434 
01435             pipefile = dfs_generate_filename_tfits(spectral_resolution_tag);
01436             if (fors_qc_write_string("PIPEFILE", pipefile,
01437                                     "Pipeline product name", instrume))
01438                 vimos_calib_exit("Cannot write PIPEFILE to QC log file");
01439             cpl_free(pipefile); pipefile = NULL;
01440 
01441 
01442             /*
01443              * QC1 parameters
01444              */
01445 
01446             keyname = "QC.MOS.RESOLUTION";
01447 
01448             if (fors_qc_write_qc_double(qclist, 
01449                                        cpl_table_get_column_mean(restab,
01450                                                                  "resolution"),
01451                                        keyname,
01452                                        "Angstrom",
01453                                        "Mean spectral resolution",
01454                                        instrume)) {
01455                 vimos_calib_exit("Cannot write mean spectral resolution to QC "
01456                                 "log file");
01457             }
01458 
01459             keyname = "QC.MOS.RESOLUTION.RMS";
01460 
01461             if (fors_qc_write_qc_double(qclist, 
01462                                        cpl_table_get_column_stdev(restab, 
01463                                                                   "resolution"),
01464                                        "QC.MOS.RESOLUTION.RMS",
01465                                        "Angstrom", 
01466                                        "Scatter of spectral resolution",
01467                                        instrume)) {
01468                 vimos_calib_exit("Cannot write spectral resolution scatter "
01469                                 "to QC log file");
01470             }
01471 
01472             keyname = "QC.MOS.RESOLUTION.NLINES";
01473 
01474             if (fors_qc_write_qc_int(qclist, cpl_table_get_nrow(restab) -
01475                                     cpl_table_count_invalid(restab, 
01476                                                             "resolution"),
01477                                     "QC.MOS.RESOLUTION.NLINES",
01478                                     NULL,
01479                                     "Number of lines for spectral resolution "
01480                                     "computation",
01481                                     instrume)) {
01482                 vimos_calib_exit("Cannot write number of lines used in "
01483                                 "spectral resolution computation "
01484                                 "to QC log file");
01485             }
01486 
01487             fors_qc_end_group();
01488 
01489         }
01490 
01491         if (dfs_save_table(frameset, restab, spectral_resolution_tag, qclist,
01492                            parlist, recipe, version))
01493             vimos_calib_exit(NULL);
01494 
01495         cpl_propertylist_delete(qclist); qclist = NULL;
01496 
01497     }
01498     else
01499         vimos_calib_exit("Cannot compute the spectral resolution table");
01500 
01501     cpl_vector_delete(lines); lines = NULL;
01502 
01503     if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
01504                        parlist, recipe, version))
01505         vimos_calib_exit(NULL);
01506 
01507     /*
01508      * Global distortion models
01509      */
01510 
01511     if (slit_ident) {
01512 
01513         cpl_msg_info(recipe, "Computing global distortions model");
01514         global = mos_global_distortion(slits, maskslits, idscoeff, 
01515                                        polytraces, reference);
01516 
01517         if (global && 0) {
01518             cpl_table *stest;
01519             cpl_table *ctest;
01520             cpl_table *dtest;
01521             cpl_image *itest;
01522 
01523             stest = mos_build_slit_location(global, maskslits, ccd_ysize);
01524 
01525             ctest = mos_build_curv_coeff(global, maskslits, stest);
01526             if (dfs_save_table(frameset, ctest, "CURVS", NULL,
01527                                parlist, recipe, version))
01528                 vimos_calib_exit(NULL);
01529 
01530             itest = mos_spatial_calibration(spectra, stest, ctest, 
01531                                             reference, startwavelength, 
01532                                             endwavelength, dispersion, 
01533                                             0, NULL);
01534             cpl_table_delete(ctest); ctest = NULL;
01535             cpl_image_delete(itest); itest = NULL;
01536             if (dfs_save_table(frameset, stest, "SLITS", NULL,
01537                                parlist, recipe, version))
01538                 vimos_calib_exit(NULL);
01539 
01540             dtest = mos_build_disp_coeff(global, stest);
01541             if (dfs_save_table(frameset, dtest, "DISPS", NULL,
01542                                parlist, recipe, version))
01543                 vimos_calib_exit(NULL);
01544 
01545             cpl_table_delete(dtest); dtest = NULL;
01546             cpl_table_delete(stest); stest = NULL;
01547         }
01548 
01549         if (global) {
01550             if (dfs_save_table(frameset, global, global_distortion_tag, NULL,
01551                                parlist, recipe, version))
01552                 vimos_calib_exit(NULL);
01553             cpl_table_delete(global); global = NULL;
01554         }
01555 
01556 //        cpl_image_delete(spectra); spectra = NULL;
01557         cpl_table_delete(maskslits); maskslits = NULL;
01558     }
01559 
01560     header = dfs_load_header(frameset, arc_tag, 0);
01561     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01562     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01563     cpl_propertylist_update_double(header, "CRVAL1", 
01564                                    startwavelength + dispersion/2);
01565     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01566     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01567     cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01568     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01569     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01570     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01571     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01572     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01573     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01574     cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1);
01575 
01576     if (qc) {
01577 
01578         double scale;
01579         double slit_width;
01580         float  lambdaHe;
01581         float  lambdaNe;
01582         float  lambdaAr;
01583         float  lambdaRed;
01584         float  lambdaYel;
01585         float  lambdaBlu;
01586         double flux, flux_err, resol, resol_err;
01587         int    selected;
01588         int    cslit = mos_slit_closest_to_center(slits, nx, ny);
01589 
01590 
01591         /*
01592          * QC1 group header
01593          */
01594 
01595         fors_qc_start_group(header, "1.1", instrume);
01596 
01597         if (fors_qc_write_string("PRO.CATG", master_norm_flat_tag,
01598                                  "Product category", instrume))
01599             vimos_calib_exit("Cannot write product category to QC log file");
01600 
01601         if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
01602                                    "Archive File Name", instrume))
01603             vimos_calib_exit("Missing keyword ARCFILE in arc lamp frame");
01604 
01605         if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
01606                                    "Template signature ID", instrume))
01607             vimos_calib_exit("Missing keyword TPL ID in arc lamp frame");
01608 
01609         if (fors_qc_keyword_to_paf(header, "ESO OCS CON QUAD", NULL,
01610                                    "Quadrant", instrume))
01611             vimos_calib_exit("Missing keyword OCS CON QUAD in arc lamp frame");
01612 
01613         if (fors_qc_keyword_to_paf(header, key_filt_name, NULL,
01614                                    "Filter", instrume)) {
01615             cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame",
01616                           key_filt_name);
01617             vimos_calib_exit(NULL);
01618         }
01619 
01620         if (fors_qc_keyword_to_paf(header, key_gris_name, NULL,
01621                                    "Grism", instrume)) {
01622             cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame",
01623                           key_gris_name);
01624             vimos_calib_exit(NULL);
01625         }
01626 
01627         if (fors_qc_keyword_to_paf(header, key_mask_id, NULL,
01628                                    "Mask", instrume)) {
01629             cpl_msg_error(recipe, "Missing keyword %s in arc lamp frame",
01630                           key_mask_id);
01631             vimos_calib_exit(NULL);
01632         }
01633 
01634         cpl_propertylist_update_double(header,
01635                                        "ESO PRO WLEN CEN", reference);
01636 
01637         if (fors_qc_keyword_to_paf(header, "ESO PRO WLEN CEN", "Angstrom",
01638                                    "Reference wavelength", instrume))
01639             vimos_calib_exit("Missing keyword PRO WLEN CEN in arc lamp frame");
01640 
01641         pipefile = dfs_generate_filename_tfits(master_norm_flat_tag);
01642         if (fors_qc_write_string("PIPEFILE", pipefile,
01643                                 "Pipeline product name", instrume))
01644             vimos_calib_exit("Cannot write PIPEFILE to QC log file");
01645         cpl_free(pipefile); pipefile = NULL;
01646 
01647         scale = cpl_propertylist_get_double(header, "ESO TEL FOCU SCALE");
01648 
01649         if (cpl_error_get_code()) {
01650             cpl_error_reset();
01651             scale = 1.718;
01652             cpl_msg_warning(recipe, "Cannot read keyword TEL FOCU SCALE "
01653                             "(defaulted to %f arcsec/mm)", scale);
01654         }
01655 
01656         /*
01657          * QC1 parameters
01658          */
01659 
01660         keyname = "QC.MOS.SLIT.WIDTH";
01661 
01662         slit_width = scale * cpl_table_get(slits, "ywidth", cslit, NULL);
01663 
01664         if (fors_qc_write_qc_double(header, slit_width, keyname, "arcsec",
01665                                     "Width of slit closest to center",
01666                                     instrume)) {
01667             vimos_calib_exit("Cannot write slit width to QC log file");
01668         }
01669 
01670         if (grism[0] == 'L') {
01671             if (grism[3] == 'r') {      /* LR_red    */
01672                 lambdaHe  = 7065.19;
01673                 lambdaNe  = 0.0;
01674                 lambdaAr  = 7723.80;
01675                 lambdaRed = 9122.97;
01676                 lambdaYel = 7635.11;
01677                 lambdaBlu = 5875.62;
01678             }
01679             if (grism[3] == 'b') {      /* LR_blue   */
01680                 lambdaHe  = 5015.68;
01681                 lambdaNe  = 6598.96;
01682                 lambdaAr  = 0.0;
01683                 lambdaRed = 6598.95;
01684                 lambdaYel = 5015.68;
01685                 lambdaBlu = 3888.65;
01686             }
01687         }
01688 
01689         if (grism[0] == 'M') {          /* MR        */
01690             lambdaHe  = 7065.19;
01691             lambdaNe  = 7032.41;
01692             lambdaAr  = 7723.80;
01693             lambdaRed = 8264.521;
01694             lambdaYel = 6678.200;
01695             lambdaBlu = 5015.675;
01696         }
01697 
01698         if (grism[0] == 'H') {
01699             if (grism[3] == 'r') {      /* HR_red    */
01700                 lambdaHe  = 7065.19;
01701                 lambdaNe  = 7032.41;
01702                 lambdaAr  = 7723.80;
01703                 lambdaRed = 9122.966;
01704                 lambdaYel = 7948.175;
01705                 lambdaBlu = 6929.468;
01706             }
01707             if (grism[3] == 'o') {      /* HR_orange */
01708                 lambdaHe  = 7065.19;
01709                 lambdaNe  = 7032.41;
01710                 lambdaAr  = 7723.80;
01711                 lambdaRed = 7948.175;
01712                 lambdaYel = 6929.468;
01713                 lambdaBlu = 5875.618;
01714             }
01715             if (grism[3] == 'b') {      /* HR_blue   */
01716                 lambdaHe  = 5015.68;
01717                 lambdaNe  = 5944.83;
01718                 lambdaAr  = 0.0;
01719                 lambdaRed = 6598.953;
01720                 lambdaYel = 5875.618;
01721                 lambdaBlu = 5015.675;
01722             }
01723         }
01724 
01725         if (lambdaHe > 1.) {
01726             mos_extract_flux_mapped(rectified, slits, lambdaHe, 
01727                                     startwavelength, dispersion, 
01728                                     4, gain, &flux, &flux_err);
01729 
01730             flux     /= arctime;
01731             flux_err /= arctime;
01732 
01733             cpl_msg_info(recipe, "Flux of He %.2f: %.2f +/- %.2f ADU/mm^2/s",
01734                          lambdaHe, flux, flux_err);
01735 
01736             keyname = "QC.MOS.HE.LAMBDA";
01737 
01738             if (fors_qc_write_qc_double(header, lambdaHe, keyname, "Angstrom",
01739                       "He arc lamp line for flux determination", instrume)) {
01740                 vimos_calib_exit("Cannot write He arc line to QC log file");
01741             }
01742 
01743             keyname = "QC.MOS.HE.FLUX";
01744 
01745             if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s",
01746                       "Flux at chosen He wavelength", instrume)) {
01747                 vimos_calib_exit("Cannot write He flux to QC log file");
01748             }
01749 
01750             keyname = "QC.MOS.HE.FLUXERR";
01751 
01752             if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s",
01753                       "Error on flux at chosen He wavelength", instrume)) {
01754                 vimos_calib_exit("Cannot write He flux error to QC log file");
01755             }
01756         }
01757         else
01758             cpl_msg_warning(recipe, 
01759                             "No He lines in %s spectral range: corresponding "
01760                             "QC1 parameters are not computed.", grism);
01761 
01762         if (lambdaNe > 1.) {
01763             mos_extract_flux_mapped(rectified, slits, lambdaNe, 
01764                                     startwavelength, dispersion, 
01765                                     4, gain, &flux, &flux_err);
01766 
01767             flux     /= arctime;
01768             flux_err /= arctime;
01769 
01770             cpl_msg_info(recipe, "Flux of Ne %.2f: %.2f +/- %.2f ADU/mm^2/s",
01771                          lambdaNe, flux, flux_err);
01772 
01773             keyname = "QC.MOS.NE.LAMBDA";
01774 
01775             if (fors_qc_write_qc_double(header, lambdaNe, keyname, "Angstrom",
01776                       "Ne arc lamp line for flux determination", instrume)) {
01777                 vimos_calib_exit("Cannot write Ne arc line to QC log file");
01778             }
01779 
01780             keyname = "QC.MOS.NE.FLUX";
01781 
01782             if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s",
01783                       "Flux at chosen Ne wavelength", instrume)) {
01784                 vimos_calib_exit("Cannot write Ne flux to QC log file");
01785             }
01786 
01787             keyname = "QC.MOS.NE.FLUXERR";
01788 
01789             if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s",
01790                       "Error on flux at chosen Ne wavelength", instrume)) {
01791                 vimos_calib_exit("Cannot write Ne flux error to QC log file");
01792             }
01793         }
01794         else
01795             cpl_msg_warning(recipe, 
01796                             "No Ne lines in %s spectral range: corresponding "
01797                             "QC1 parameters are not computed.", grism);
01798 
01799         if (lambdaAr > 1.) {
01800             mos_extract_flux_mapped(rectified, slits, lambdaAr, 
01801                                     startwavelength, dispersion, 
01802                                     4, gain, &flux, &flux_err);
01803 //            mos_extract_flux(spectra, slits, 3, gain, &flux, &flux_err);
01804 
01805             flux     /= arctime;
01806             flux_err /= arctime;
01807 
01808             cpl_msg_info(recipe, "Flux of Ar %.2f: %.2f +/- %.2f ADU/mm^2/s",
01809                          lambdaAr, flux, flux_err);
01810 
01811             keyname = "QC.MOS.AR.LAMBDA";
01812 
01813             if (fors_qc_write_qc_double(header, lambdaAr, keyname, "Angstrom",
01814                       "Ar arc lamp line for flux determination", instrume)) {
01815                 vimos_calib_exit("Cannot write Ar arc line to QC log file");
01816             }
01817 
01818             keyname = "QC.MOS.AR.FLUX";
01819 
01820             if (fors_qc_write_qc_double(header, flux, keyname, "ADU/mm^2/s",
01821                       "Flux at chosen Ar wavelength", instrume)) {
01822                 vimos_calib_exit("Cannot write Ar flux to QC log file");
01823             }
01824 
01825             keyname = "QC.MOS.AR.FLUXERR";
01826 
01827             if (fors_qc_write_qc_double(header, flux_err, keyname, "ADU/mm^2/s",
01828                       "Error on flux at chosen Ar wavelength", instrume)) {
01829                 vimos_calib_exit("Cannot write Ar flux error to QC log file");
01830             }
01831         }
01832         else
01833             cpl_msg_warning(recipe, 
01834                             "No Ar lines in %s spectral range: corresponding "
01835                             "QC1 parameters are not computed.", grism);
01836 
01837         /*
01838          * IDS coefficients
01839          */
01840 
01841         for (i = 0; i <= wdegree; i++) {
01842             char  *label = cpl_sprintf("c%d", i);
01843             char  *unit;
01844             char  *comment;
01845             double mcoeff;
01846 
01847 
01848             mcoeff = 0.0;    // Zero by definition when i == 0
01849             if (i) {
01850                 if (mos_median_in_slit(idscoeff, slits, 
01851                                        cslit, label, &mcoeff)) {
01852                     cpl_free(label);
01853                     break;
01854                 }
01855             }
01856 
01857             keyname = cpl_sprintf("QC.MOS.WAVECAL.COEFF%d", i);
01858 
01859             switch (i) {
01860             case 0:
01861                 unit = cpl_strdup("pixel");
01862                 break;
01863             case 1:
01864                 unit = cpl_strdup("pixel/Angstrom");
01865                 break;
01866             default:
01867                 unit = cpl_sprintf("pixel/Angstrom^%d", i);
01868                 break;
01869             }
01870 
01871             comment = cpl_sprintf("Median coefficient %d of IDS", i);
01872 
01873             if (fors_qc_write_qc_double(header, mcoeff, keyname, 
01874                                         unit, comment, instrume)) {
01875                 vimos_calib_exit("Cannot write IDS coefficient to QC logfile");
01876             }
01877 
01878             cpl_free(keyname);
01879             cpl_free(comment);
01880             cpl_free(unit);
01881             cpl_free(label);
01882         }
01883 
01884         /*
01885          * These parameters are now useless, I set them to zero.
01886          */
01887 
01888         keyname = "QC.MOS.REFWAVE.MEAN";
01889 
01890         if (fors_qc_write_qc_double(header, 0.0, keyname, "pixel", 
01891                 "MEAN of CCD positions of reference wavelength", instrume)) {
01892             vimos_calib_exit("Cannot write QC.MOS.REFWAVE.MEAN to QC logfile");
01893         }
01894 
01895         keyname = "QC.MOS.REFWAVE.RMS";
01896 
01897         if (fors_qc_write_qc_double(header, 0.0, keyname, "pixel", 
01898                 "RMS of CCD positions of reference wavelength", instrume)) {
01899             vimos_calib_exit("Cannot write QC.MOS.REFWAVE.RMS to QC logfile");
01900         }
01901 
01902         if (restab) {
01903 
01904             /*
01905              * About spectral resolution:
01906              */
01907 
01908             keyname = "QC.MOS.RESOLUTION1.LAMBDA";
01909 
01910             if (fors_qc_write_qc_double(header, lambdaRed, keyname, "Angstrom",
01911                 "Line used in spectral resolution determination", instrume)) {
01912                 vimos_calib_exit("Cannot write arc line to QC log file");
01913             }
01914 
01915             keyname = "QC.MOS.RESOLUTION1";
01916 
01917             cpl_table_and_selected_double(restab, "wavelength", 
01918                                           CPL_GREATER_THAN, lambdaRed - 1.0);
01919             selected =
01920             cpl_table_and_selected_double(restab, "wavelength", 
01921                                           CPL_LESS_THAN, lambdaRed + 1.0);
01922 
01923             if (selected == 1) {
01924                 cpl_table *one_line = cpl_table_extract_selected(restab);
01925 
01926                 resol = cpl_table_get_double(one_line, 
01927                                              "resolution", 0, NULL);
01928                 resol_err = cpl_table_get_double(one_line, 
01929                                              "resolution_rms", 0, NULL);
01930 
01931                 cpl_table_delete(one_line);
01932             }
01933             else {
01934                 resol = 0.0;
01935                 resol_err = 0.0;
01936             }
01937     
01938             cpl_table_select_all(restab);
01939     
01940             cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f",
01941                          lambdaRed, resol, resol_err);
01942     
01943             if (fors_qc_write_qc_double(header, resol, keyname, NULL,
01944                 "Mean spectral resolution at red end of spectrum", instrume)) {
01945                 vimos_calib_exit("Cannot write spectral resolution "
01946                                  "to QC log file");
01947             }
01948     
01949             keyname = "QC.MOS.RESOLUTION1.RMS";
01950 
01951             if (fors_qc_write_qc_double(header, resol_err, keyname, NULL,
01952                 "Error on mean spectral resolution", instrume)) {
01953                 vimos_calib_exit("Cannot write error on resolution "
01954                                  "to QC log file");
01955             }
01956 
01957             keyname = "QC.MOS.RESOLUTION2.LAMBDA";
01958 
01959             if (fors_qc_write_qc_double(header, lambdaYel, keyname, "Angstrom",
01960                 "Line used in spectral resolution determination", instrume)) {
01961                 vimos_calib_exit("Cannot write arc line to QC log file");
01962             }
01963 
01964             keyname = "QC.MOS.RESOLUTION2";
01965 
01966             cpl_table_and_selected_double(restab, "wavelength",
01967                                           CPL_GREATER_THAN, lambdaYel - 1.0);
01968             selected =
01969             cpl_table_and_selected_double(restab, "wavelength",
01970                                           CPL_LESS_THAN, lambdaYel + 1.0);
01971 
01972             if (selected == 1) {
01973                 cpl_table *one_line = cpl_table_extract_selected(restab);
01974     
01975                 resol = cpl_table_get_double(one_line, 
01976                                              "resolution", 0, NULL);
01977                 resol_err = cpl_table_get_double(one_line, 
01978                                              "resolution_rms", 0, NULL);
01979 
01980                 cpl_table_delete(one_line);
01981             }
01982             else {
01983                 resol = 0.0;
01984                 resol_err = 0.0;
01985             }
01986 
01987             cpl_table_select_all(restab);
01988     
01989             cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f",
01990                          lambdaYel, resol, resol_err);
01991 
01992             if (fors_qc_write_qc_double(header, resol, keyname, NULL,
01993                 "Mean spectral resolution at center of spectrum", instrume)) {
01994                 vimos_calib_exit("Cannot write spectral resolution "
01995                                  "to QC log file");
01996             }
01997 
01998             keyname = "QC.MOS.RESOLUTION2.RMS";
01999 
02000             if (fors_qc_write_qc_double(header, resol_err, keyname, NULL,
02001                 "Error on mean spectral resolution", instrume)) {
02002                 vimos_calib_exit("Cannot write error on resolution "
02003                                      "to QC log file");
02004             }
02005 
02006             keyname = "QC.MOS.RESOLUTION3.LAMBDA";
02007 
02008             if (fors_qc_write_qc_double(header, lambdaBlu, keyname, "Angstrom",
02009                 "Line used in spectral resolution determination", instrume)) {
02010                 vimos_calib_exit("Cannot write arc line to QC log file");
02011             }
02012 
02013             keyname = "QC.MOS.RESOLUTION3";
02014 
02015             cpl_table_and_selected_double(restab, "wavelength",
02016                                           CPL_GREATER_THAN, lambdaBlu - 1.0);
02017             selected =
02018             cpl_table_and_selected_double(restab, "wavelength",
02019                                           CPL_LESS_THAN, lambdaBlu + 1.0);
02020 
02021             if (selected == 1) {
02022                 cpl_table *one_line = cpl_table_extract_selected(restab);
02023     
02024                 resol = cpl_table_get_double(one_line, 
02025                                              "resolution", 0, NULL);
02026                 resol_err = cpl_table_get_double(one_line, 
02027                                              "resolution_rms", 0, NULL);
02028     
02029                 cpl_table_delete(one_line);
02030             }
02031             else {
02032                 resol = 0.0;
02033                 resol_err = 0.0;
02034             }
02035 
02036             cpl_table_select_all(restab);
02037 
02038             cpl_msg_info(recipe, "Spectral resolution at %.2f: %.2f +/- %.2f",
02039                          lambdaBlu, resol, resol_err);
02040 
02041             if (fors_qc_write_qc_double(header, resol, keyname, NULL,
02042                 "Mean spectral resolution at blue end of spectrum", instrume)) {
02043                 vimos_calib_exit("Cannot write spectral resolution "
02044                                  "to QC log file");
02045             }
02046 
02047             keyname = "QC.MOS.RESOLUTION3.RMS";
02048 
02049             if (fors_qc_write_qc_double(header, resol_err, keyname, NULL,
02050                 "Error on mean spectral resolution", instrume)) {
02051                 vimos_calib_exit("Cannot write error on resolution "
02052                                  "to QC log file");
02053             }
02054 
02055             keyname = "QC.MOS.IDS.RMS";
02056 
02057             if (fors_qc_write_qc_double(header, mean_rms, keyname, "pixel",
02058                 "Mean accuracy of dispersion solution", instrume)) {
02059                 vimos_calib_exit("Cannot write mean accuracy of "
02060                                  "dispersion solution to QC log file");
02061             }
02062         }
02063 
02064         fors_qc_end_group();
02065 
02066     }
02067 
02068     cpl_free(grism); grism = NULL;
02069     cpl_free(instrume); instrume = NULL;
02070     cpl_table_delete(restab); restab = NULL;
02071     cpl_table_delete(idscoeff); idscoeff = NULL;
02072     cpl_image_delete(spectra); spectra = NULL;
02073 
02074     if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header,
02075                        parlist, recipe, version))
02076         vimos_calib_exit(NULL);
02077 
02078     cpl_image_delete(rectified); rectified = NULL;
02079     cpl_propertylist_delete(header); header = NULL;
02080 
02081     if (check) {
02082         save_header = dfs_load_header(frameset, arc_tag, 0);
02083 
02084         cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
02085         cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
02086         /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
02087         cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
02088         cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
02089         cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
02090         cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
02091         cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
02092         cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
02093 
02094         if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header,
02095                            parlist, recipe, version))
02096             vimos_calib_exit(NULL);
02097 
02098         cpl_image_delete(residual); residual = NULL;
02099         cpl_propertylist_delete(save_header); save_header = NULL;
02100     }
02101 
02102     if (!treat_as_lss) {
02103 
02104         /*
02105          * Wavemap was already produced if treat_as_lss = true
02106          */
02107 
02108         wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 
02109                                       polytraces, reference, 
02110                                       startwavelength, endwavelength, 
02111                                       dispersion);
02112 
02113         cpl_image_delete(rainbow); rainbow = NULL;
02114     }
02115 
02116     save_header = dfs_load_header(frameset, arc_tag, 0);
02117 
02118     cpl_image_turn(wavemap, rotate_back);
02119     if (dfs_save_image(frameset, wavemap, wavelength_map_tag, save_header,
02120                        parlist, recipe, version))
02121         vimos_calib_exit(NULL);
02122 
02123     cpl_image_delete(wavemap); wavemap = NULL;
02124 
02125     cpl_image_turn(coordinate, rotate_back);
02126     if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header,
02127                        parlist, recipe, version))
02128         vimos_calib_exit(NULL);
02129 
02130     cpl_image_delete(coordinate); coordinate = NULL;
02131     cpl_propertylist_delete(save_header); save_header = NULL;
02132 
02133     if (dfs_save_table(frameset, polytraces, curv_coeff_tag, NULL,
02134                        parlist, recipe, version))
02135         vimos_calib_exit(NULL);
02136 
02137     cpl_table_delete(polytraces); polytraces = NULL;
02138 
02139     mos_rotate_slits(slits, rotate, ccd_ysize, ccd_xsize);
02140     if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
02141                        parlist, recipe, version))
02142         vimos_calib_exit(NULL);
02143 
02144     cpl_table_delete(slits); slits = NULL;
02145 
02146     if (cpl_error_get_code()) {
02147         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
02148         vimos_calib_exit(NULL);
02149     }
02150 
02151     return 0;
02152 }

Generated on Fri Mar 4 09:46:01 2011 for FORS Pipeline Reference Manual by  doxygen 1.4.7