fors_pmos_calib.c

00001 /* $Id: fors_pmos_calib.c,v 1.34 2010/09/14 07:38:16 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:38:16 $
00024  * $Revision: 1.34 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <string.h>
00034 #include <ctype.h>
00035 #include <cpl.h>
00036 #include <moses.h>
00037 #include <fors_stack.h>
00038 #include <fors_dfs.h>
00039 #include <fors_qc.h>
00040 
00041 #define OFFSET    50
00042 #define TOLERANCE 10
00043 
00044 static int fors_pmos_calib_create(cpl_plugin *);
00045 static int fors_pmos_calib_exec(cpl_plugin *);
00046 static int fors_pmos_calib_destroy(cpl_plugin *);
00047 static int fors_pmos_calib(cpl_parameterlist *, cpl_frameset *);
00048 
00049 static char fors_pmos_calib_description[] =
00050 "This recipe is used to identify reference lines on PMOS arc lamp\n"
00051 "exposures, and trace the spectral edges on the corresponding flat field\n"
00052 "exposures. This information is used to determine the spectral extraction\n"
00053 "mask to be applied in the scientific data reduction, performed with the\n"
00054 "recipe fors_science.\n"
00055 "This recipe accepts both FORS1 and FORS2 frames. The input arc lamps and\n"
00056 "flat field exposures are assumed to be obtained quasi-simultaneously, so\n"
00057 "that they would be described by exactly the same instrument distortions.\n"
00058 "A line catalog must be specified, containing the wavelengths of the\n"
00059 "reference arc lamp lines used for the wavelength calibration. A grism\n"
00060 "table (typically depending on the instrument mode, and in particular on\n"
00061 "the grism used) may also be specified: this table contains a default\n"
00062 "recipe parameter setting to control the way spectra are extracted for\n"
00063 "a specific instrument mode, as it is used for automatic run of the\n"
00064 "pipeline on Paranal and in Garching. If this table is specified, it\n"
00065 "will modify the default recipe parameter setting, with the exception of\n"
00066 "those parameters which have been explicitly modifyed on the command line.\n"
00067 "If a grism table is not specified, the input recipe parameters values\n"
00068 "will always be read from the command line, or from an esorex configuration\n"
00069 "file if present, or from their generic default values (that are rarely\n"
00070 "meaningful). Finally a master bias frame must be input to this recipe.\n" 
00071 "The products SPECTRA_DETECTION_PMOS, SLIT_MAP_PMOS, and DISP_RESIDUALS_PMOS,\n"
00072 "are just created if the --check parameter is set to true.\n"
00073 "The MASTER_DISTORTION_TABLE is marked as required, but it is not so if all\n"
00074 "slits have different offsets, and in the case of FORS1 observations made\n"
00075 "with the old TK2048EB4-1 1604 chip read in windowed mode (2048x400)\n\n" 
00076 "Input files:\n\n"
00077 "  DO category:              Type:       Explanation:          Required:\n"
00078 "  SCREEN_FLAT_PMOS          Raw         Flat field exposures     Y\n"
00079 "  LAMP_PMOS                 Raw         Arc lamp exposure        Y\n"
00080 "  MASTER_BIAS or BIAS       Calib       Bias frame               Y\n"
00081 "  MASTER_LINECAT            Calib       Line catalog             Y\n"
00082 "  GRISM_TABLE               Calib       Grism table              .\n"
00083 "  MASTER_DISTORTION_TABLE   Calib       Master distortions table Y\n\n"
00084 "Output files:\n\n" 
00085 "  DO category:              Data type:  Explanation:\n"
00086 "  MASTER_SCREEN_FLAT_PMOS   FITS image  Combined (sum) flat field\n"
00087 "  MASTER_NORM_FLAT_PMOS     FITS image  Normalised flat field\n"
00088 "  MAPPED_SCREEN_FLAT_PMOS   FITS image  Wavelength calibrated flat field\n"
00089 "  MAPPED_NORM_FLAT_PMOS     FITS image  Wavelength calibrated normalised flat\n"
00090 "  REDUCED_LAMP_PMOS         FITS image  Wavelength calibrated arc spectrum\n"
00091 "  DISP_COEFF_PMOS           FITS table  Inverse dispersion coefficients\n"
00092 "  DISP_RESIDUALS_PMOS       FITS image  Residuals in wavelength calibration\n"
00093 "  DISP_RESIDUALS_TABLE_PMOS FITS table  Residuals in wavelength calibration\n"
00094 "  DELTA_IMAGE_PMOS          FITS image  Offset vs linear wavelength calib\n"
00095 "  WAVELENGTH_MAP_PMOS       FITS image  Wavelength for each pixel on CCD\n"
00096 "  SPECTRA_DETECTION_PMOS    FITS image  Check for preliminary detection\n"
00097 "  SLIT_MAP_PMOS             FITS image  Map of central wavelength on CCD\n"
00098 "  CURV_TRACES_PMOS          FITS table  Spectral curvature traces\n"
00099 "  CURV_COEFF_PMOS           FITS table  Spectral curvature coefficients\n"
00100 "  SPATIAL_MAP_PMOS          FITS image  Spatial position along slit on CCD\n"
00101 "  SPECTRAL_RESOLUTION_PMOS  FITS table  Resolution at reference arc lines\n"
00102 "  SLIT_LOCATION_PMOS        FITS table  Slits on product frames and CCD\n\n";
00103 
00104 #define fors_pmos_calib_exit(message)              \
00105 {                                             \
00106 if (message) cpl_msg_error(recipe, message);  \
00107 cpl_free(instrume);                           \
00108 cpl_free(pipefile);                           \
00109 cpl_free(fiterror);                           \
00110 cpl_free(fitlines);                           \
00111 cpl_image_delete(bias);                       \
00112 cpl_image_delete(master_bias);                \
00113 cpl_image_delete(coordinate);                 \
00114 cpl_image_delete(checkwave);                  \
00115 cpl_image_delete(flat);                       \
00116 cpl_image_delete(master_flat);                \
00117 cpl_image_delete(added_flat);                 \
00118 cpl_image_delete(norm_flat);                  \
00119 cpl_image_delete(mapped_flat);                \
00120 cpl_image_delete(mapped_nflat);               \
00121 cpl_image_delete(rainbow);                    \
00122 cpl_image_delete(rectified);                  \
00123 cpl_image_delete(residual);                   \
00124 cpl_image_delete(smo_flat);                   \
00125 cpl_image_delete(spatial);                    \
00126 cpl_image_delete(spectra);                    \
00127 cpl_image_delete(wavemap);                    \
00128 cpl_image_delete(delta);                      \
00129 cpl_image_delete(rect_flat);                  \
00130 cpl_image_delete(rect_nflat);                 \
00131 cpl_image_delete(mapped_flat);                \
00132 cpl_image_delete(mapped_nflat);               \
00133 cpl_mask_delete(refmask);                     \
00134 cpl_propertylist_delete(header);              \
00135 cpl_propertylist_delete(save_header);         \
00136 cpl_propertylist_delete(qclist);              \
00137 cpl_table_delete(grism_table);                \
00138 cpl_table_delete(idscoeff);                   \
00139 cpl_table_delete(idscoeff_all);               \
00140 cpl_table_delete(restable);                   \
00141 cpl_table_delete(maskslits);                  \
00142 cpl_table_delete(overscans);                  \
00143 cpl_table_delete(traces);                     \
00144 cpl_table_delete(polytraces);                 \
00145 cpl_table_delete(slits);                      \
00146 cpl_table_delete(restab);                     \
00147 cpl_table_delete(global);                     \
00148 cpl_table_delete(wavelengths);                \
00149 cpl_vector_delete(lines);                     \
00150 cpl_msg_indent_less();                        \
00151 return -1;                                    \
00152 }
00153 
00154 #define fors_pmos_calib_exit_memcheck(message)       \
00155 {                                               \
00156 if (message) cpl_msg_info(recipe, message);     \
00157 printf("free instrume (%p)\n", instrume);       \
00158 cpl_free(instrume);                             \
00159 printf("free pipefile (%p)\n", pipefile);       \
00160 cpl_free(pipefile);                             \
00161 printf("free fiterror (%p)\n", fiterror);       \
00162 cpl_free(fiterror);                             \
00163 printf("free fitlines (%p)\n", fitlines);       \
00164 cpl_free(fitlines);                             \
00165 printf("free bias (%p)\n", bias);               \
00166 cpl_image_delete(bias);                         \
00167 printf("free master_bias (%p)\n", master_bias); \
00168 cpl_image_delete(master_bias);                  \
00169 printf("free coordinate (%p)\n", coordinate);   \
00170 cpl_image_delete(coordinate);                   \
00171 printf("free checkwave (%p)\n", checkwave);     \
00172 cpl_image_delete(checkwave);                    \
00173 printf("free flat (%p)\n", flat);               \
00174 cpl_image_delete(flat);                         \
00175 printf("free master_flat (%p)\n", master_flat); \
00176 cpl_image_delete(master_flat);                  \
00177 printf("free norm_flat (%p)\n", norm_flat);     \
00178 cpl_image_delete(norm_flat);                    \
00179 printf("free mapped_flat (%p)\n", mapped_flat); \
00180 cpl_image_delete(mapped_flat);                  \
00181 printf("free mapped_nflat (%p)\n", mapped_nflat); \
00182 cpl_image_delete(mapped_nflat);                 \
00183 printf("free rainbow (%p)\n", rainbow);         \
00184 cpl_image_delete(rainbow);                      \
00185 printf("free rectified (%p)\n", rectified);     \
00186 cpl_image_delete(rectified);                    \
00187 printf("free residual (%p)\n", residual);       \
00188 cpl_image_delete(residual);                     \
00189 printf("free smo_flat (%p)\n", smo_flat);       \
00190 cpl_image_delete(smo_flat);                     \
00191 printf("free spatial (%p)\n", spatial);         \
00192 cpl_image_delete(spatial);                      \
00193 printf("free spectra (%p)\n", spectra);         \
00194 cpl_image_delete(spectra);                      \
00195 printf("free wavemap (%p)\n", wavemap);         \
00196 cpl_image_delete(wavemap);                      \
00197 printf("free delta (%p)\n", delta);             \
00198 cpl_image_delete(delta);                        \
00199 printf("free rect_flat (%p)\n", rect_flat);     \
00200 cpl_image_delete(rect_flat);                    \
00201 printf("free rect_nflat (%p)\n", rect_nflat);   \
00202 cpl_image_delete(rect_nflat);                   \
00203 printf("free refmask (%p)\n", refmask);         \
00204 cpl_mask_delete(refmask);                       \
00205 printf("free header (%p)\n", header);           \
00206 cpl_propertylist_delete(header);                \
00207 printf("free save_header (%p)\n", save_header); \
00208 cpl_propertylist_delete(save_header);           \
00209 printf("free qclist (%p)\n", qclist);           \
00210 cpl_propertylist_delete(qclist);                \
00211 printf("free grism_table (%p)\n", grism_table); \
00212 cpl_table_delete(grism_table);                  \
00213 printf("free idscoeff (%p)\n", idscoeff);       \
00214 cpl_table_delete(idscoeff);                     \
00215 printf("free idscoeff_all (%p)\n", idscoeff_all);  \
00216 cpl_table_delete(idscoeff_all);                 \
00217 printf("free restable (%p)\n", restable);       \
00218 cpl_table_delete(restable);                     \
00219 printf("free maskslits (%p)\n", maskslits);     \
00220 cpl_table_delete(maskslits);                    \
00221 printf("free overscans (%p)\n", overscans);     \
00222 cpl_table_delete(overscans);                    \
00223 printf("free traces (%p)\n", traces);           \
00224 cpl_table_delete(traces);                       \
00225 printf("free polytraces (%p)\n", polytraces);   \
00226 cpl_table_delete(polytraces);                   \
00227 printf("free slits (%p)\n", slits);             \
00228 cpl_table_delete(slits);                        \
00229 printf("free restab (%p)\n", restab);           \
00230 cpl_table_delete(restab);                       \
00231 printf("free global (%p)\n", global);           \
00232 cpl_table_delete(global);                       \
00233 printf("free wavelengths (%p)\n", wavelengths); \
00234 cpl_table_delete(wavelengths);                  \
00235 printf("free lines (%p)\n", lines);             \
00236 cpl_vector_delete(lines);                       \
00237 cpl_msg_indent_less();                          \
00238 return 0;                                       \
00239 }
00240 
00241 
00253 int cpl_plugin_get_info(cpl_pluginlist *list)
00254 {
00255     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00256     cpl_plugin *plugin = &recipe->interface;
00257 
00258     cpl_plugin_init(plugin,
00259                     CPL_PLUGIN_API,
00260                     FORS_BINARY_VERSION,
00261                     CPL_PLUGIN_TYPE_RECIPE,
00262                     "fors_pmos_calib",
00263                     "Determination of the extraction mask",
00264                     fors_pmos_calib_description,
00265                     "Carlo Izzo",
00266                     PACKAGE_BUGREPORT,
00267     "This file is currently part of the FORS Instrument Pipeline\n"
00268     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00269     "This program is free software; you can redistribute it and/or modify\n"
00270     "it under the terms of the GNU General Public License as published by\n"
00271     "the Free Software Foundation; either version 2 of the License, or\n"
00272     "(at your option) any later version.\n\n"
00273     "This program is distributed in the hope that it will be useful,\n"
00274     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00275     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00276     "GNU General Public License for more details.\n\n"
00277     "You should have received a copy of the GNU General Public License\n"
00278     "along with this program; if not, write to the Free Software Foundation,\n"
00279     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00280                     fors_pmos_calib_create,
00281                     fors_pmos_calib_exec,
00282                     fors_pmos_calib_destroy);
00283 
00284     cpl_pluginlist_append(list, plugin);
00285     
00286     return 0;
00287 }
00288 
00289 
00300 static int fors_pmos_calib_create(cpl_plugin *plugin)
00301 {
00302     cpl_recipe    *recipe;
00303     cpl_parameter *p;
00304 
00305 
00306     /* 
00307      * Check that the plugin is part of a valid recipe 
00308      */
00309 
00310     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00311         recipe = (cpl_recipe *)plugin;
00312     else 
00313         return -1;
00314 
00315     /* 
00316      * Create the parameters list in the cpl_recipe object 
00317      */
00318 
00319     recipe->parameters = cpl_parameterlist_new(); 
00320 
00321 
00322     /*
00323      * Dispersion
00324      */
00325 
00326     p = cpl_parameter_new_value("fors.fors_pmos_calib.dispersion",
00327                                 CPL_TYPE_DOUBLE,
00328                                 "Expected spectral dispersion (Angstrom/pixel)",
00329                                 "fors.fors_pmos_calib",
00330                                 0.0);
00331     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00332     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00333     cpl_parameterlist_append(recipe->parameters, p);
00334 
00335     /*
00336      * Peak detection level
00337      */
00338 
00339     p = cpl_parameter_new_value("fors.fors_pmos_calib.peakdetection",
00340                                 CPL_TYPE_DOUBLE,
00341                                 "Initial peak detection threshold (ADU)",
00342                                 "fors.fors_pmos_calib",
00343                                 0.0);
00344     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00345     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00346     cpl_parameterlist_append(recipe->parameters, p);
00347 
00348     /* 
00349      * Degree of wavelength calibration polynomial
00350      */
00351 
00352     p = cpl_parameter_new_value("fors.fors_pmos_calib.wdegree",
00353                                 CPL_TYPE_INT,
00354                                 "Degree of wavelength calibration polynomial",
00355                                 "fors.fors_pmos_calib",
00356                                 0);
00357     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00358     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00359     cpl_parameterlist_append(recipe->parameters, p);
00360 
00361     /*
00362      * Reference lines search radius
00363      */
00364 
00365     p = cpl_parameter_new_value("fors.fors_pmos_calib.wradius",
00366                                 CPL_TYPE_INT,
00367                                 "Search radius if iterating pattern-matching "
00368                                 "with first-guess method",
00369                                 "fors.fors_pmos_calib",
00370                                 4);
00371     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00372     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00373     cpl_parameterlist_append(recipe->parameters, p);
00374 
00375     /*
00376      * Rejection threshold in dispersion relation polynomial fitting
00377      */
00378 
00379     p = cpl_parameter_new_value("fors.fors_pmos_calib.wreject",
00380                                 CPL_TYPE_DOUBLE,
00381                                 "Rejection threshold in dispersion "
00382                                 "relation fit (pixel)",
00383                                 "fors.fors_pmos_calib",
00384                                 0.7);
00385     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00386     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00387     cpl_parameterlist_append(recipe->parameters, p);
00388 
00389     /*
00390      * Line catalog table column containing the reference wavelengths
00391      */
00392 
00393     p = cpl_parameter_new_value("fors.fors_pmos_calib.wcolumn",
00394                                 CPL_TYPE_STRING,
00395                                 "Name of line catalog table column "
00396                                 "with wavelengths",
00397                                 "fors.fors_pmos_calib",
00398                                 "WLEN");
00399     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00400     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00401     cpl_parameterlist_append(recipe->parameters, p);
00402 
00403     /*
00404      * Degree of spectral curvature polynomial
00405      */
00406 
00407     p = cpl_parameter_new_value("fors.fors_pmos_calib.cdegree",
00408                                 CPL_TYPE_INT,
00409                                 "Degree of spectral curvature polynomial",
00410                                 "fors.fors_pmos_calib",
00411                                 0);
00412     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree");
00413     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00414     cpl_parameterlist_append(recipe->parameters, p);
00415 
00416     /*
00417      * Curvature solution interpolation
00418      */
00419  
00420     p = cpl_parameter_new_value("fors.fors_pmos_calib.cmode",
00421                                 CPL_TYPE_INT,
00422                                 "Interpolation mode of curvature solution "
00423                                 "(0 = no "
00424                                 "interpolation, 1 = fill gaps, 2 = global "
00425                                 "model)",
00426                                 "fors.fors_pmos_calib",
00427                                 1);
00428     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode");
00429     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00430     cpl_parameterlist_append(recipe->parameters, p);
00431 
00432     /*
00433      * Start wavelength for spectral extraction
00434      */
00435 
00436     p = cpl_parameter_new_value("fors.fors_pmos_calib.startwavelength",
00437                                 CPL_TYPE_DOUBLE,
00438                                 "Start wavelength in spectral extraction",
00439                                 "fors.fors_pmos_calib",
00440                                 0.0);
00441     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00442     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00443     cpl_parameterlist_append(recipe->parameters, p);
00444 
00445     /*
00446      * End wavelength for spectral extraction
00447      */
00448 
00449     p = cpl_parameter_new_value("fors.fors_pmos_calib.endwavelength",
00450                                 CPL_TYPE_DOUBLE,
00451                                 "End wavelength in spectral extraction",
00452                                 "fors.fors_pmos_calib",
00453                                 0.0);
00454     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00455     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00456     cpl_parameterlist_append(recipe->parameters, p);
00457 
00458     /*
00459      * Flat field frames stack parameters
00460      */
00461  
00462     fors_stack_define_parameters(recipe->parameters, "fors.fors_pmos_calib", 
00463                                  "average");
00464 
00465     /*
00466      * Degree of flat field fitting polynomial along dispersion direction
00467      */
00468 
00469     p = cpl_parameter_new_value("fors.fors_pmos_calib.ddegree",
00470                                 CPL_TYPE_INT,
00471                                 "Degree of flat field fitting polynomial "
00472                                 "along dispersion direction",
00473                                 "fors.fors_pmos_calib",
00474                                 -1);
00475     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree");
00476     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00477     cpl_parameterlist_append(recipe->parameters, p);
00478 
00479     /*
00480      * Smooth box radius for flat field along dispersion direction
00481      */
00482 
00483     p = cpl_parameter_new_value("fors.fors_pmos_calib.dradius",
00484                                 CPL_TYPE_INT,
00485                                 "Smooth box radius for flat field along "
00486                                 "dispersion direction",
00487                                 "fors.fors_pmos_calib",
00488                                 10);
00489     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius");
00490     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00491     cpl_parameterlist_append(recipe->parameters, p);
00492 
00493     /*
00494      * Computation of QC1 parameters
00495      */
00496 
00497     p = cpl_parameter_new_value("fors.fors_pmos_calib.qc",
00498                                 CPL_TYPE_BOOL,
00499                                 "Compute QC1 parameters",
00500                                 "fors.fors_pmos_calib",
00501                                 TRUE);
00502     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc");
00503     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00504     cpl_parameterlist_append(recipe->parameters, p);
00505 
00506     /*
00507      * Create check products
00508      */
00509 
00510     p = cpl_parameter_new_value("fors.fors_pmos_calib.check",
00511                                 CPL_TYPE_BOOL,
00512                                 "Create intermediate products",
00513                                 "fors.fors_pmos_calib",
00514                                 FALSE);
00515     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check");
00516     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00517     cpl_parameterlist_append(recipe->parameters, p);
00518 
00519     return 0;
00520 }
00521 
00522 
00531 static int fors_pmos_calib_exec(cpl_plugin *plugin)
00532 {
00533     cpl_recipe *recipe;
00534     
00535     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00536         recipe = (cpl_recipe *)plugin;
00537     else 
00538         return -1;
00539 
00540     return fors_pmos_calib(recipe->parameters, recipe->frames);
00541 }
00542 
00543 
00552 static int fors_pmos_calib_destroy(cpl_plugin *plugin)
00553 {
00554     cpl_recipe *recipe;
00555     
00556     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00557         recipe = (cpl_recipe *)plugin;
00558     else 
00559         return -1;
00560 
00561     cpl_parameterlist_delete(recipe->parameters); 
00562 
00563     return 0;
00564 }
00565 
00566 
00576 static int fors_pmos_calib(cpl_parameterlist *parlist, cpl_frameset *frameset)
00577 {
00578 
00579     const char *recipe = "fors_pmos_calib";
00580 
00581 
00582     /*
00583      * Input parameters
00584      */
00585 
00586     double      dispersion;
00587     double      peakdetection;
00588     int         wdegree;
00589     int         wradius;
00590     double      wreject;
00591     const char *wcolumn;
00592     int         cdegree;
00593     int         cmode;
00594     double      startwavelength;
00595     double      endwavelength;
00596     int         ddegree;
00597     int         dradius;
00598     int         qc;
00599     int         check;
00600     const char *stack_method;
00601     int         min_reject;
00602     int         max_reject;
00603     double      klow;
00604     double      khigh;
00605     int         kiter;
00606 
00607 
00608     /*
00609      * CPL objects
00610      */
00611 
00612     cpl_imagelist    *biases       = NULL;
00613     cpl_image        *bias         = NULL;
00614     cpl_image        *master_bias  = NULL;
00615     cpl_image        *multi_bias   = NULL;
00616     cpl_image        *flat         = NULL;
00617     cpl_image        *master_flat  = NULL;
00618     cpl_image        *added_flat   = NULL;
00619     cpl_image        *trace_flat   = NULL;
00620     cpl_image        *smo_flat     = NULL;
00621     cpl_image        *norm_flat    = NULL;
00622     cpl_image        *spectra      = NULL;
00623     cpl_image        *wavemap      = NULL;
00624     cpl_image        *delta        = NULL;
00625     cpl_image        *residual     = NULL;
00626     cpl_image        *checkwave    = NULL;
00627     cpl_image        *rectified    = NULL;
00628     cpl_image        *dummy        = NULL;
00629     cpl_image        *add_dummy    = NULL;
00630     cpl_image        *refimage     = NULL;
00631     cpl_image        *coordinate   = NULL;
00632     cpl_image        *rainbow      = NULL;
00633     cpl_image        *spatial      = NULL;
00634     cpl_image        *rect_flat    = NULL;
00635     cpl_image        *rect_nflat   = NULL;
00636     cpl_image        *mapped_flat  = NULL;
00637     cpl_image        *mapped_nflat = NULL;
00638 
00639     cpl_mask         *refmask      = NULL;
00640 
00641     cpl_table        *grism_table  = NULL;
00642     cpl_table        *overscans    = NULL;
00643     cpl_table        *wavelengths  = NULL;
00644     cpl_table        *idscoeff     = NULL;
00645     cpl_table        *idscoeff_all = NULL;
00646     cpl_table        *restable     = NULL;
00647     cpl_table        *slits        = NULL;
00648     cpl_table        *positions    = NULL;
00649     cpl_table        *maskslits    = NULL;
00650     cpl_table        *traces       = NULL;
00651     cpl_table        *polytraces   = NULL;
00652     cpl_table        *restab       = NULL;
00653     cpl_table        *global       = NULL;
00654 
00655     cpl_vector       *lines        = NULL;
00656 
00657     cpl_propertylist *header_dist  = NULL;
00658     cpl_propertylist *header       = NULL;
00659     cpl_propertylist *save_header  = NULL;
00660     cpl_propertylist *qclist       = NULL;
00661 
00662     /*
00663      * Auxiliary variables
00664      */
00665 
00666     char    version[80];
00667     const char   *arc_tag;
00668     const char   *flat_tag;
00669     const char   *master_screen_flat_tag;
00670     const char   *master_norm_flat_tag;
00671     const char   *reduced_lamp_tag;
00672     const char   *disp_residuals_tag;
00673     const char   *disp_coeff_tag;
00674     const char   *wavelength_map_tag;
00675     const char   *spectra_detection_tag;
00676     const char   *spectral_resolution_tag;
00677     const char   *slit_map_tag;
00678     const char   *curv_traces_tag;
00679     const char   *curv_coeff_tag;
00680     const char   *spatial_map_tag;
00681     const char   *slit_location_tag;
00682     const char   *master_distortion_tag = "MASTER_DISTORTION_TABLE";
00683     const char   *disp_residuals_table_tag;
00684     const char   *delta_image_tag;
00685     const char   *mapped_screen_flat_tag;
00686     const char   *mapped_norm_flat_tag;
00687     const char   *keyname;
00688     int     pmos;
00689     int     same_offset = 0;
00690     int     nslits;
00691     float  *data;
00692     double *xpos;
00693     double  mxpos;
00694     double  mean_rms;
00695     double  mean_rms_err;
00696     double  alltime;
00697     int     nflats;
00698     int     nbias;
00699     int     nlines;
00700     int     rebin, rebin_dist;
00701     double *line;
00702     double *fiterror = NULL;
00703     int    *fitlines = NULL;
00704     int     nx, ny;
00705     double  reference;
00706     double  gain;
00707     int     ccd_xsize, ccd_ysize;
00708     int     i, j;
00709 
00710     char   *instrume = NULL;
00711     char   *pipefile = NULL;
00712 
00713     /*
00714      * Variables just related to bagoo
00715      */
00716 
00717     int     bagoo = 0;
00718     int     doit = 0;
00719     double  blevel = 0.0;
00720     double  ron = 0.0;
00721 
00722     snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00723 
00724     cpl_msg_set_indentation(2);
00725 
00726     if (dfs_files_dont_exist(frameset))
00727         fors_pmos_calib_exit(NULL);
00728 
00729     fors_dfs_set_groups(frameset);
00730 
00731     /* 
00732      * Get configuration parameters
00733      */
00734 
00735     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00736     cpl_msg_indent_more();
00737 
00738     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00739         fors_pmos_calib_exit("Too many in input: GRISM_TABLE");
00740 
00741     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00742 
00743     dispersion = dfs_get_parameter_double(parlist, 
00744                     "fors.fors_pmos_calib.dispersion", grism_table);
00745 
00746     if (dispersion <= 0.0)
00747         fors_pmos_calib_exit("Invalid spectral dispersion value");
00748 
00749     peakdetection = dfs_get_parameter_double(parlist, 
00750                     "fors.fors_pmos_calib.peakdetection", grism_table);
00751     if (peakdetection <= 0.0)
00752         fors_pmos_calib_exit("Invalid peak detection level");
00753 
00754     wdegree = dfs_get_parameter_int(parlist, 
00755                     "fors.fors_pmos_calib.wdegree", grism_table);
00756 
00757     if (wdegree < 1)
00758         fors_pmos_calib_exit("Invalid polynomial degree");
00759 
00760     if (wdegree > 5)
00761         fors_pmos_calib_exit("Max allowed polynomial degree is 5");
00762 
00763     wradius = dfs_get_parameter_int(parlist, 
00764                                     "fors.fors_pmos_calib.wradius", NULL);
00765 
00766     if (wradius < 0)
00767         fors_pmos_calib_exit("Invalid search radius");
00768 
00769     wreject = dfs_get_parameter_double(parlist, 
00770                                        "fors.fors_pmos_calib.wreject", NULL);
00771 
00772     if (wreject <= 0.0)
00773         fors_pmos_calib_exit("Invalid rejection threshold");
00774 
00775     wcolumn = dfs_get_parameter_string(parlist, 
00776                                        "fors.fors_pmos_calib.wcolumn", NULL);
00777 
00778     cdegree = dfs_get_parameter_int(parlist, 
00779                     "fors.fors_pmos_calib.cdegree", grism_table);
00780 
00781     if (cdegree < 1)
00782         fors_pmos_calib_exit("Invalid polynomial degree");
00783 
00784     if (cdegree > 5)
00785         fors_pmos_calib_exit("Max allowed polynomial degree is 5");
00786 
00787     cmode = dfs_get_parameter_int(parlist, "fors.fors_pmos_calib.cmode", NULL);
00788 
00789     if (cmode < 0 || cmode > 2)
00790         fors_pmos_calib_exit("Invalid curvature solution interpolation mode");
00791 
00792     startwavelength = dfs_get_parameter_double(parlist, 
00793                     "fors.fors_pmos_calib.startwavelength", grism_table);
00794     if (startwavelength > 1.0)
00795         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00796             fors_pmos_calib_exit("Invalid wavelength");
00797 
00798     endwavelength = dfs_get_parameter_double(parlist, 
00799                     "fors.fors_pmos_calib.endwavelength", grism_table);
00800     if (endwavelength > 1.0) {
00801         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00802             fors_pmos_calib_exit("Invalid wavelength");
00803         if (startwavelength < 1.0)
00804             fors_pmos_calib_exit("Invalid wavelength interval");
00805     }
00806 
00807     if (startwavelength > 1.0)
00808         if (endwavelength - startwavelength <= 0.0)
00809             fors_pmos_calib_exit("Invalid wavelength interval");
00810 
00811     stack_method = dfs_get_parameter_string(parlist,
00812                                             "fors.fors_pmos_calib.stack_method",
00813                                             NULL);
00814 
00815     if (strcmp(stack_method, "minmax") == 0) {
00816         min_reject = dfs_get_parameter_int(parlist,
00817                                    "fors.fors_pmos_calib.minrejection", NULL);
00818         if (min_reject < 0)
00819             fors_pmos_calib_exit("Invalid number of lower rejections");
00820 
00821         max_reject = dfs_get_parameter_int(parlist,
00822                                    "fors.fors_pmos_calib.maxrejection", NULL);
00823         if (max_reject < 0)
00824             fors_pmos_calib_exit("Invalid number of upper rejections");
00825     }
00826 
00827     if (strcmp(stack_method, "ksigma") == 0) {
00828         klow  = dfs_get_parameter_double(parlist,
00829                                          "fors.fors_pmos_calib.klow", NULL);
00830         if (klow < 0.1)
00831             fors_pmos_calib_exit("Invalid lower K-sigma");
00832 
00833         khigh = dfs_get_parameter_double(parlist,
00834                                          "fors.fors_pmos_calib.khigh", NULL);
00835         if (khigh < 0.1)
00836             fors_pmos_calib_exit("Invalid lower K-sigma");
00837 
00838         kiter = dfs_get_parameter_int(parlist,
00839                                       "fors.fors_pmos_calib.kiter", NULL);
00840         if (kiter < 1)
00841             fors_pmos_calib_exit("Invalid number of iterations");
00842     }
00843 
00844     ddegree = dfs_get_parameter_int(parlist, 
00845                                     "fors.fors_pmos_calib.ddegree", NULL);
00846     dradius = dfs_get_parameter_int(parlist, 
00847                                     "fors.fors_pmos_calib.dradius", NULL);
00848 
00849     if (dradius < 1)
00850         fors_pmos_calib_exit("Invalid smoothing box radius");
00851 
00852     qc = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.qc", NULL);
00853 
00854     check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.check", NULL);
00855 
00856     cpl_table_delete(grism_table); grism_table = NULL;
00857 
00858     if (cpl_error_get_code())
00859         fors_pmos_calib_exit("Failure getting the configuration parameters");
00860 
00861 
00862     /* 
00863      * Check input set-of-frames
00864      */
00865 
00866     cpl_msg_indent_less();
00867     cpl_msg_info(recipe, "Check input set-of-frames:");
00868     cpl_msg_indent_more();
00869 
00870     {
00871         cpl_frameset *subframeset = cpl_frameset_duplicate(frameset);
00872         cpl_frameset_erase(subframeset, "BIAS");
00873         cpl_frameset_erase(subframeset, "MASTER_BIAS");
00874 
00875         if (!dfs_equal_keyword(subframeset, "ESO INS GRIS1 ID")) 
00876             fors_pmos_calib_exit("Input frames are not from the same grism");
00877     
00878         if (!dfs_equal_keyword(subframeset, "ESO INS FILT1 ID")) 
00879             fors_pmos_calib_exit("Input frames are not from the same filter");
00880     
00881         if (!dfs_equal_keyword(subframeset, "ESO DET CHIP1 ID")) 
00882             fors_pmos_calib_exit("Input frames are not from the same chip");
00883 
00884         cpl_frameset_delete(subframeset);
00885     }
00886 
00887     pmos = cpl_frameset_count_tags(frameset, "LAMP_PMOS");
00888 
00889     if (pmos == 0)
00890         fors_pmos_calib_exit("Missing input arc lamp frame");
00891 
00892     if (pmos) {
00893         cpl_msg_info(recipe, "PMOS data found");
00894         arc_tag                  = "LAMP_PMOS";
00895         flat_tag                 = "SCREEN_FLAT_PMOS";
00896         master_screen_flat_tag   = "MASTER_SCREEN_FLAT_PMOS";
00897         master_norm_flat_tag     = "MASTER_NORM_FLAT_PMOS";
00898         reduced_lamp_tag         = "REDUCED_LAMP_PMOS";
00899         disp_residuals_tag       = "DISP_RESIDUALS_PMOS";
00900         disp_coeff_tag           = "DISP_COEFF_PMOS";
00901         wavelength_map_tag       = "WAVELENGTH_MAP_PMOS";
00902         spectra_detection_tag    = "SPECTRA_DETECTION_PMOS";
00903         spectral_resolution_tag  = "SPECTRAL_RESOLUTION_PMOS";
00904         slit_map_tag             = "SLIT_MAP_PMOS";
00905         curv_traces_tag          = "CURV_TRACES_PMOS";
00906         curv_coeff_tag           = "CURV_COEFF_PMOS";
00907         spatial_map_tag          = "SPATIAL_MAP_PMOS";
00908         slit_location_tag        = "SLIT_LOCATION_PMOS";
00909         disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_PMOS";
00910         delta_image_tag          = "DELTA_IMAGE_PMOS";
00911         mapped_screen_flat_tag   = "MAPPED_SCREEN_FLAT_PMOS";
00912         mapped_norm_flat_tag     = "MAPPED_NORM_FLAT_PMOS";
00913     }
00914 
00915     nbias = 0;
00916     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) {
00917         if (cpl_frameset_count_tags(frameset, "BIAS") == 0)
00918             fors_pmos_calib_exit("Missing required input: MASTER_BIAS or BIAS");
00919         nbias = cpl_frameset_count_tags(frameset, "BIAS");
00920     }
00921 
00922     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00923         fors_pmos_calib_exit("Too many in input: MASTER_BIAS");
00924 
00925     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00926         fors_pmos_calib_exit("Missing required input: MASTER_LINECAT");
00927 
00928     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00929         fors_pmos_calib_exit("Too many in input: MASTER_LINECAT");
00930 
00931     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00932         fors_pmos_calib_exit("Missing required input: MASTER_LINECAT");
00933 
00934     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00935         fors_pmos_calib_exit("Too many in input: MASTER_LINECAT");
00936 
00937 /*
00938     if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0)
00939         fors_pmos_calib_exit("Missing required input: MASTER_DISTORTION_TABLE");
00940 */
00941 
00942     if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1)
00943         fors_pmos_calib_exit("Too many in input: MASTER_DISTORTION_TABLE");
00944 
00945     nflats = cpl_frameset_count_tags(frameset, flat_tag);
00946 
00947     if (nflats < 1) {
00948         cpl_msg_error(recipe, "Missing required input: %s", flat_tag);
00949         fors_pmos_calib_exit(NULL);
00950     }
00951 
00952     cpl_msg_indent_less();
00953 
00954     if (nflats > 1)
00955         cpl_msg_info(recipe, "Load %d flat field frames and stack them "
00956                      "with method \"%s\"", nflats, stack_method);
00957     else
00958         cpl_msg_info(recipe, "Load flat field exposure...");
00959 
00960     cpl_msg_indent_more();
00961 
00962     header = dfs_load_header(frameset, flat_tag, 0);
00963 
00964     if (header == NULL)
00965         fors_pmos_calib_exit("Cannot load flat field frame header");
00966 
00967     alltime = cpl_propertylist_get_double(header, "EXPTIME");
00968 
00969     if (cpl_error_get_code() != CPL_ERROR_NONE)
00970         fors_pmos_calib_exit("Missing keyword EXPTIME in flat field "
00971                              "frame header");
00972 
00973     cpl_propertylist_delete(header);
00974 
00975     for (i = 1; i < nflats; i++) {
00976 
00977         header = dfs_load_header(frameset, NULL, 0);
00978 
00979         if (header == NULL)
00980             fors_pmos_calib_exit("Cannot load flat field frame header");
00981 
00982         alltime += cpl_propertylist_get_double(header, "EXPTIME");
00983 
00984         if (cpl_error_get_code() != CPL_ERROR_NONE)
00985             fors_pmos_calib_exit("Missing keyword EXPTIME in flat field "
00986                             "frame header");
00987 
00988         cpl_propertylist_delete(header);
00989 
00990     }
00991 
00992     if (bagoo) {
00993         char *montecarlo = getenv("MONTECARLO");
00994 
00995         if (montecarlo)
00996             doit = atoi(montecarlo);
00997 
00998         if (doit) {
00999             master_bias = dfs_load_image(frameset, "MASTER_BIAS",
01000                                      CPL_TYPE_FLOAT, 0, 1);
01001             if (master_bias == NULL)
01002                 fors_pmos_calib_exit("Cannot load master bias");
01003 
01004             blevel = cpl_image_get_mean(master_bias);
01005 
01006             cpl_image_delete(master_bias);
01007         }
01008     }
01009 
01010     master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0);
01011 
01012     if (master_flat == NULL)
01013         fors_pmos_calib_exit("Cannot load flat field");
01014 
01015     if (doit) {
01016         header = dfs_load_header(frameset, flat_tag, 0);
01017 
01018         gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01019 
01020         if (cpl_error_get_code() != CPL_ERROR_NONE)
01021             fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD "
01022                                  "in flat field frame header");
01023 
01024         ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01025 
01026         if (cpl_error_get_code() != CPL_ERROR_NONE)
01027             fors_pmos_calib_exit("Missing keyword ESO DET OUT1 RON "
01028                                  "in flat field frame header");
01029 
01030         cpl_propertylist_delete(header);
01031 
01032         ron /= gain;   // RON converted from electrons to ADU
01033 
01034         mos_randomise_image(master_flat, ron, gain, blevel);
01035     }
01036 
01037     ny = cpl_image_get_size_y(master_flat);
01038 
01039     if (nflats > 1) {
01040         if (strcmp(stack_method, "average") == 0) {
01041             for (i = 1; i < nflats; i++) {
01042                 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01043                 if (flat) {
01044                     if (doit) {
01045                         mos_randomise_image(flat, ron, gain, blevel);
01046                     }
01047                     cpl_image_add(master_flat, flat);
01048                     cpl_image_delete(flat); flat = NULL;
01049                 }
01050                 else
01051                     fors_pmos_calib_exit("Cannot load flat field");
01052             }
01053 
01054         /***
01055             if (nflats > 1)
01056                 cpl_image_divide_scalar(master_flat, nflats);
01057         ***/
01058 
01059         }
01060         else {
01061             cpl_imagelist *flatlist = NULL;
01062             double rflux, flux;
01063 
01064             added_flat = cpl_image_duplicate(master_flat);
01065 
01066             flatlist = cpl_imagelist_new();
01067             cpl_imagelist_set(flatlist, master_flat, 
01068                               cpl_imagelist_get_size(flatlist));
01069 
01070             /*
01071              * Stacking with rejection requires normalization
01072              * at the same flux. We normalise according to mean
01073              * flux. This is equivalent to determining the
01074              * flux ratio for each image as the average of the
01075              * flux ratio of all pixels weighted on the actual
01076              * flux of each pixel.
01077              */
01078 
01079             rflux = cpl_image_get_mean(master_flat);
01080 
01081             for (i = 1; i < nflats; i++) {
01082                 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01083                 if (flat) {
01084                     if (doit) {
01085                         mos_randomise_image(flat, ron, gain, blevel);
01086                     }
01087                     cpl_image_add(added_flat, flat);
01088                     flux = cpl_image_get_mean(flat);
01089                     cpl_image_multiply_scalar(flat, rflux / flux);
01090                     cpl_imagelist_set(flatlist, flat, 
01091                                       cpl_imagelist_get_size(flatlist));
01092                 }
01093                 else {
01094                     fors_pmos_calib_exit("Cannot load flat field");
01095                 }
01096             }
01097             
01098             if (strcmp(stack_method, "median") == 0) {
01099                 master_flat = cpl_imagelist_collapse_median_create(flatlist);
01100             }
01101 
01102             if (strcmp(stack_method, "minmax") == 0) {
01103                 master_flat = cpl_imagelist_collapse_minmax_create(flatlist, 
01104                                                                    min_reject,
01105                                                                    max_reject);
01106             }
01107 
01108             if (strcmp(stack_method, "ksigma") == 0) {
01109                 master_flat = mos_ksigma_stack(flatlist, 
01110                                                klow, khigh, kiter, NULL);
01111             }
01112         }
01113     }
01114 
01115 
01116     /*
01117      * Get the reference wavelength and the rebin factor along the
01118      * dispersion direction from the arc lamp exposure
01119      */
01120 
01121     header = dfs_load_header(frameset, arc_tag, 0);
01122 
01123     if (header == NULL)
01124         fors_pmos_calib_exit("Cannot load arc lamp header");
01125 
01126     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
01127     if (instrume == NULL)
01128         fors_pmos_calib_exit("Missing keyword INSTRUME in arc lamp header");
01129 
01130     instrume = cpl_strdup(instrume);
01131 
01132     if (instrume[4] == '1')
01133         snprintf(version, 80, "%s/%s", "fors1", VERSION);
01134     if (instrume[4] == '2')
01135         snprintf(version, 80, "%s/%s", "fors2", VERSION);
01136 
01137     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
01138 
01139     if (cpl_error_get_code() != CPL_ERROR_NONE)
01140         fors_pmos_calib_exit("Missing keyword ESO INS GRIS1 WLEN in arc lamp "
01141                         "frame header");
01142 
01143     if (reference < 3000.0)   /* Perhaps in nanometers... */
01144         reference *= 10;
01145 
01146     if (reference < 3000.0 || reference > 13000.0) {
01147         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01148                       "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
01149                       reference);
01150         fors_pmos_calib_exit(NULL);
01151     }
01152 
01153     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01154 
01155     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01156 
01157     if (cpl_error_get_code() != CPL_ERROR_NONE)
01158         fors_pmos_calib_exit("Missing keyword ESO DET WIN1 BINX in arc lamp "
01159                         "frame header");
01160 
01161     if (rebin != 1) {
01162         dispersion *= rebin;
01163         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01164                         "working dispersion used is %f A/pixel", rebin, 
01165                         dispersion);
01166     }
01167 
01168     gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01169 
01170     if (cpl_error_get_code() != CPL_ERROR_NONE)
01171         fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp "
01172                         "frame header");
01173 
01174     cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01175 
01176     if (pmos) {
01177         cpl_msg_info(recipe, "Produce mask slit position table...");
01178 
01179         maskslits = mos_load_slits_fors_mos(header);
01180 
01181         /*
01182          * Check if all slits have the same X offset: in such case, 
01183          * treat the observation as a long-slit one!
01184          */
01185 
01186         mxpos = cpl_table_get_column_median(maskslits, "xtop");
01187         xpos = cpl_table_get_data_double(maskslits, "xtop");
01188         nslits = cpl_table_get_nrow(maskslits);
01189 
01190         same_offset = 1;
01191         for (i = 0; i < nslits; i++) {
01192             if (fabs(mxpos-xpos[i]) > 0.01) {
01193                 same_offset = 0;
01194                 break;
01195             }
01196         }
01197 
01198         if (same_offset) {
01199             cpl_msg_info(recipe, "All slits have same offset: %.2f", mxpos);
01200         }
01201         else {
01202             cpl_msg_info(recipe, "All slits have different offsets");
01203         }
01204 
01205         if (ny != 400 && ny != 500) {
01206             if (cpl_frameset_count_tags(frameset, 
01207                                         master_distortion_tag) == 0)
01208                 fors_pmos_calib_exit(
01209                 "Missing required input: MASTER_DISTORTION_TABLE");
01210 
01211             header_dist = dfs_load_header(frameset, 
01212                                           master_distortion_tag, 0);
01213             rebin_dist = cpl_propertylist_get_int(header_dist,
01214                                                   "ESO DET WIN1 BINX");
01215             cpl_propertylist_delete(header_dist);
01216         }
01217     }
01218 
01219     /* Leave the header on for the next step... */
01220 
01221 
01222     /*
01223      * Remove the master bias
01224      */
01225 
01226     if (nbias) {
01227 
01228         /*
01229          * Set of raw BIASes in input, need to create master bias!
01230          */
01231 
01232         cpl_msg_info(recipe, "Generate the master from input raw biases...");
01233 
01234         if (nbias > 1) {
01235 
01236             biases = cpl_imagelist_new();
01237 
01238             bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0);
01239     
01240             if (bias == NULL)
01241                 fors_pmos_calib_exit("Cannot load bias frame");
01242 
01243             cpl_imagelist_set(biases, bias, 0);
01244     
01245             for (i = 1; i < nbias; i++) {
01246                 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01247                 if (bias)
01248                     cpl_imagelist_set(biases, bias, i);
01249                 else
01250                     fors_pmos_calib_exit("Cannot load bias frame");
01251             }
01252     
01253             master_bias = cpl_imagelist_collapse_median_create(biases);
01254 
01255             cpl_imagelist_delete(biases);
01256         }
01257         else {
01258             master_bias = dfs_load_image(frameset, "BIAS", 
01259                                          CPL_TYPE_FLOAT, 0, 1);
01260             if (master_bias == NULL)
01261                 fors_pmos_calib_exit("Cannot load bias");
01262         }
01263 
01264     }
01265     else {
01266         master_bias = dfs_load_image(frameset, "MASTER_BIAS", 
01267                                      CPL_TYPE_FLOAT, 0, 1);
01268         if (master_bias == NULL)
01269             fors_pmos_calib_exit("Cannot load master bias");
01270     }
01271 
01272     cpl_msg_info(recipe, "Remove the master bias...");
01273 
01274     overscans = mos_load_overscans_fors(header);
01275     cpl_propertylist_delete(header); header = NULL;
01276 
01277     if (nbias) {
01278         int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL);
01279         int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL);
01280         int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL);
01281         int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL);
01282         dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig);
01283         cpl_image_delete(master_bias); master_bias = dummy;
01284 
01285         if (dfs_save_image(frameset, master_bias, "MASTER_BIAS",
01286                            NULL, parlist, recipe, version))
01287             fors_pmos_calib_exit(NULL);
01288     }
01289 
01290     if (nflats > 1) {
01291         multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats);
01292         dummy = mos_remove_bias(master_flat, multi_bias, overscans);
01293         if (added_flat)
01294             add_dummy = mos_remove_bias(added_flat, multi_bias, overscans);
01295         cpl_image_delete(multi_bias);
01296     }
01297     else {
01298         dummy = mos_remove_bias(master_flat, master_bias, overscans);
01299     }
01300     cpl_image_delete(master_flat);
01301     master_flat = dummy;
01302 
01303     if (master_flat == NULL)
01304         fors_pmos_calib_exit("Cannot remove bias from flat field");
01305 
01306     if (added_flat) {
01307         cpl_image_delete(added_flat);
01308         added_flat = add_dummy;
01309 
01310         if (added_flat == NULL)
01311             fors_pmos_calib_exit("Cannot remove bias from added flat field");
01312 
01313         trace_flat = added_flat;
01314     }
01315     else
01316         trace_flat = master_flat;
01317 
01318     wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
01319 
01320     if (wavelengths == NULL)
01321         fors_pmos_calib_exit("Cannot load line catalog");
01322 
01323     /*
01324      * Cast the wavelengths into a (double precision) CPL vector
01325      */
01326 
01327     nlines = cpl_table_get_nrow(wavelengths);
01328 
01329     if (nlines == 0)
01330         fors_pmos_calib_exit("Empty input line catalog");
01331 
01332     if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01333         cpl_msg_error(recipe, "Missing column %s in input line catalog table",
01334                       wcolumn);
01335         fors_pmos_calib_exit(NULL);
01336     }
01337 
01338     line = cpl_malloc(nlines * sizeof(double));
01339     
01340     for (i = 0; i < nlines; i++)
01341         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01342 
01343     lines = cpl_vector_wrap(nlines, line);
01344 
01345     for (j = 0; j < pmos; j++) {
01346         int k;
01347 
01348         cpl_msg_indent_less();
01349         cpl_msg_info(recipe, "Processing arc lamp nb %d out of %d ...",
01350                      j + 1, pmos);
01351         cpl_msg_indent_more();
01352 
01353         cpl_msg_info(recipe, "Load arc lamp exposure...");
01354         cpl_msg_indent_more();
01355 
01356         spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
01357 
01358         /*
01359          * FIXME: Horrible workaround to avoid the problem because of the
01360          * multiple encapsulation of cpl_frameset_find() in different 
01361          * loading functions
01362          */
01363         for (k = 0; k < j; k ++) {
01364             cpl_image_delete(spectra);
01365             spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01366         }
01367 
01368         if (spectra == NULL)
01369             fors_pmos_calib_exit("Cannot load arc lamp exposure");
01370 
01371         if (doit) {
01372             mos_randomise_image(spectra, ron, gain, blevel);
01373         }
01374 
01375         cpl_msg_info(recipe, "Remove the master bias...");
01376 
01377         dummy = mos_remove_bias(spectra, master_bias, overscans);
01378         cpl_image_delete(spectra); spectra = dummy;
01379 
01380         if (spectra == NULL)
01381             fors_pmos_calib_exit("Cannot remove bias from arc lamp exposure");
01382 
01383         cpl_msg_indent_less();
01384         cpl_msg_info(recipe, "Load input line catalog...");
01385         cpl_msg_indent_more();
01386 
01387         /*
01388          * Here the PMOS calibration is carried out.
01389          */
01390 
01391         if (mos_saturation_process(spectra))
01392             fors_pmos_calib_exit("Cannot process saturation");
01393 
01394         if (mos_subtract_background(spectra))
01395             fors_pmos_calib_exit("Cannot subtract the background");
01396 
01397         if (!j) {
01398             /*
01399              * Detecting spectra on the CCD
01400              */
01401 
01402             cpl_msg_indent_less();
01403             cpl_msg_info(recipe, "Detecting spectra on CCD...");
01404             cpl_msg_indent_more();
01405 
01406             ccd_xsize = nx = cpl_image_get_size_x(spectra);
01407             ccd_ysize = ny = cpl_image_get_size_y(spectra);
01408 
01409             refmask = cpl_mask_new(nx, ny);
01410 
01411             checkwave =
01412                 mos_wavelength_calibration_raw(spectra, lines, dispersion, 
01413                                                peakdetection, wradius, 
01414                                                wdegree, wreject, reference,
01415                                                &startwavelength, &endwavelength,
01416                                                NULL, NULL, NULL, NULL, NULL, 
01417                                                NULL, refmask);
01418 
01419             if (checkwave == NULL)
01420                 fors_pmos_calib_exit("Wavelength calibration failure.");
01421 
01422             /*
01423              * Save check image to disk
01424              */
01425 
01426             header = cpl_propertylist_new();
01427             cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01428             cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01429             cpl_propertylist_update_double(header, "CRVAL1", 
01430                                            startwavelength + dispersion/2);
01431             cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01432             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01433                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01434             cpl_propertylist_update_double(header, "CD1_1", dispersion);
01435             cpl_propertylist_update_double(header, "CD1_2", 0.0);
01436             cpl_propertylist_update_double(header, "CD2_1", 0.0);
01437             cpl_propertylist_update_double(header, "CD2_2", 1.0);
01438             cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01439             cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01440 
01441             if (check) {
01442                 if (!j) {
01443                     if(dfs_save_image_null(frameset, parlist,
01444                                            spectra_detection_tag,
01445                                            recipe, version)) {
01446                         fors_pmos_calib_exit(NULL);
01447                     }
01448                 }
01449 
01450                 if (dfs_save_image_ext(checkwave, 
01451                                        spectra_detection_tag, header)) {
01452                     fors_pmos_calib_exit(NULL);
01453                 }
01454             }
01455 
01456             cpl_image_delete(checkwave); checkwave = NULL;
01457             cpl_propertylist_delete(header); header = NULL;
01458 
01459             if (cpl_mask_is_empty(refmask))
01460                 fors_pmos_calib_exit("Wavelength calibration failure.");
01461 
01462             if (mos_refmask_find_gaps(refmask, trace_flat, -1.0))
01463                 fors_pmos_calib_exit("The gaps could not be found");
01464 
01465             cpl_msg_info(recipe,
01466                          "Locate slits at reference wavelength on CCD...");
01467             slits = mos_locate_spectra(refmask);
01468 
01469             if (!slits) {
01470                 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
01471                 fors_pmos_calib_exit("No slits could be detected!");
01472             }
01473 
01474             if (same_offset) {
01475                 if (ny != 400 && ny != 500) {
01476                     float rescale = (float) rebin_dist / rebin;
01477                     if (mos_check_slits(slits, rescale)) {
01478                         fors_pmos_calib_exit("Some slits are missing. "
01479                                              "Cannot recover!");
01480                     }
01481                 }
01482             }
01483 
01484             refimage = cpl_image_new_from_mask(refmask);
01485             cpl_mask_delete(refmask); refmask = NULL;
01486 
01487             if (check) {
01488                 if (!j) {
01489                     if(dfs_save_image_null(frameset, parlist,
01490                                            slit_map_tag,
01491                                            recipe, version)) {
01492                         fors_pmos_calib_exit(NULL);
01493                     }
01494                 }
01495 
01496                 save_header = dfs_load_header(frameset, arc_tag, 0);
01497 
01498                 for (k = 0; k < j; k ++) {
01499                     cpl_propertylist_delete(save_header);
01500                     save_header = dfs_load_header(frameset, NULL, 0);
01501                 }
01502 
01503                 if (dfs_save_image_ext(refimage, slit_map_tag, save_header)) {
01504                     fors_pmos_calib_exit(NULL);
01505                 }
01506                 cpl_propertylist_delete(save_header); save_header = NULL;
01507             }
01508 
01509             cpl_image_delete(refimage); refimage = NULL;
01510 
01511 //          if (same_offset == 0) {
01512 
01513             same_offset = 1; // Added, see next line comment.
01514             if (0) { // This part is eliminated: a successful
01515                      // pattern matching would identify just 
01516                      // one of the two beams!!! It needs to be FIXED.
01517 
01518                 /*
01519                  * Attempt slit identification: this recipe may continue even
01520                  * in case of failed identification (i.e., the position table
01521                  * is not produced, but an error is not set). In case of 
01522                  * failure, the spectra would be still extracted, even if they
01523                  * would not be associated to slits on the mask.
01524                  * 
01525                  * The reason for making the slit identification an user option
01526                  * (via the parameter slit_ident) is to offer the possibility 
01527                  * to avoid identifications that are only apparently successful
01528                  * as it would happen in the case of an incorrect slit
01529                  * description in the data header.
01530                  */
01531 
01532                 cpl_msg_indent_less();
01533                 cpl_msg_info(recipe, 
01534                              "Attempt slit identification (optional)...");
01535                 cpl_msg_indent_more();
01536 
01537                 positions = mos_identify_slits(slits, maskslits, NULL);
01538 
01539                 if (positions) {
01540                     cpl_table_delete(slits);
01541                     slits = positions;
01542 
01543                    /*
01544                     * Eliminate slits which are not _entirely_ inside the CCD
01545                     */
01546 
01547                     cpl_table_and_selected_double(slits, 
01548                                                  "ytop", CPL_GREATER_THAN, ny);
01549                     cpl_table_or_selected_double(slits, 
01550                                                  "ybottom", CPL_LESS_THAN, 0);
01551                     cpl_table_erase_selected(slits);
01552 
01553                     nslits = cpl_table_get_nrow(slits);
01554 
01555                     if (nslits == 0)
01556                         fors_pmos_calib_exit("No slits found on the CCD");
01557 
01558                     cpl_msg_info(recipe,
01559                                  "%d slits are entirely contained in CCD", 
01560                                  nslits);
01561                 }
01562                 else {
01563                     same_offset = 1; /* FIXLANDER slit_ident = 0; */
01564                     cpl_msg_info(recipe, 
01565                                  "Global distortion model cannot be computed");
01566                     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01567                         fors_pmos_calib_exit(NULL);
01568                     }
01569                 }
01570             }
01571 
01572 
01573             if (ny == 400 || ny == 500) {
01574 
01575                /*
01576                 * For the FORS1 special case (old chip 2048x400 readout)
01577                 * keep the central slits only
01578                 */
01579 
01580                 nslits = cpl_table_get_nrow(slits);
01581 
01582                 if (nslits > 4) {
01583                     cpl_table_unselect_all(slits);
01584                     for (k = 0; k < cpl_table_get_nrow(slits); k++) {
01585                         double jump = cpl_table_get(slits, "ytop", k, NULL) 
01586                                     - cpl_table_get(slits, "ybottom", k, NULL);
01587                         if (jump < 50.) {
01588                             cpl_table_select_row(slits, k);
01589                         }
01590                     }
01591                     cpl_table_erase_selected(slits);
01592                     nslits = cpl_table_get_nrow(slits);
01593                 }
01594 
01595                 if (nslits == 0)
01596                     fors_pmos_calib_exit("No slits found on the CCD");
01597 
01598                 if (nslits == 4) {
01599                     cpl_table_unselect_all(slits);
01600                     cpl_table_select_row(slits, 0);
01601                     cpl_table_select_row(slits, cpl_table_get_nrow(slits)-1);
01602                     cpl_table_erase_selected(slits);
01603                 }
01604 
01605                 cpl_msg_info(recipe, 
01606                              "%d slits are entirely contained in CCD", nslits);
01607             }
01608             else {
01609                 cpl_table_unselect_all(slits);
01610                 for (k = 0; k < cpl_table_get_nrow(slits); k++) {
01611                     double jump = cpl_table_get(slits, "ytop", k, NULL)
01612                                 - cpl_table_get(slits, "ybottom", k, NULL);
01613                     if (jump < 10.) {
01614                         cpl_table_select_row(slits, k);
01615                     }
01616                 }
01617                 cpl_table_erase_selected(slits);
01618                 nslits = cpl_table_get_nrow(slits);
01619             }
01620 
01621 
01622             /*
01623              * Determination of spectral curvature
01624              */
01625 
01626             cpl_msg_indent_less();
01627             cpl_msg_info(recipe, "Determining spectral curvature...");
01628             cpl_msg_indent_more();
01629 
01630             cpl_msg_info(recipe, "Tracing master flat field spectra edges...");
01631             traces = mos_trace_flat(trace_flat, slits, reference, 
01632                                     startwavelength, endwavelength, dispersion);
01633 
01634             if (!traces)
01635                 fors_pmos_calib_exit("Tracing failure");
01636 
01637             cpl_image_delete(added_flat); added_flat = NULL;
01638 
01639             cpl_msg_info(recipe, "Fitting flat field spectra edges...");
01640             polytraces = mos_poly_trace(slits, traces, cdegree);
01641 
01642             if (!polytraces)
01643                 fors_pmos_calib_exit("Trace fitting failure");
01644 
01645             if (cmode) {
01646                 cpl_msg_info(recipe, 
01647                              "Computing global spectral curvature model...");
01648                 mos_global_trace(slits, polytraces, cmode);
01649             }
01650 
01651             if (!j) {
01652                 if(dfs_save_image_null(frameset, parlist, curv_traces_tag,
01653                                        recipe, version)) {
01654                     fors_pmos_calib_exit(NULL);
01655                 }
01656             }
01657 
01658             if (dfs_save_table_ext(traces, curv_traces_tag, NULL)) {
01659                 fors_pmos_calib_exit(NULL);
01660             }
01661 
01662             cpl_table_delete(traces); traces = NULL;
01663 
01664             coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01665 
01666         }
01667 //
01668         spatial = mos_spatial_calibration(spectra, slits, polytraces,
01669                                           reference, 
01670                                           startwavelength, endwavelength, 
01671                                           dispersion, 0, j ? NULL: coordinate);
01672 
01673         if (!j) {
01674 //
01675             if (same_offset) { /* FIXLANDER It was !slit_ident */
01676                 cpl_image_delete(spectra); spectra = NULL;
01677             }
01678 
01679             /*
01680              * Flat field normalisation is done directly on the master flat
01681              * field (without spatial rectification first). The spectral
01682              * curvature model may be provided in input, in future releases.
01683              */
01684 
01685             cpl_msg_indent_less();
01686             cpl_msg_info(recipe, "Perform flat field normalisation...");
01687             cpl_msg_indent_more();
01688 
01689             norm_flat = cpl_image_duplicate(master_flat);
01690 
01691             smo_flat = mos_normalise_flat(norm_flat, coordinate, slits,
01692                                           polytraces, reference,
01693                                           startwavelength, endwavelength,
01694                                           dispersion, dradius, ddegree);
01695 
01696             /* This may be a product */
01697             cpl_image_delete(smo_flat); smo_flat = NULL; 
01698 
01699  
01700             save_header = dfs_load_header(frameset, flat_tag, 0);
01701             cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM",
01702                                         nflats);
01703 
01704             rect_flat = mos_spatial_calibration(master_flat, slits, polytraces,
01705                                                 reference, startwavelength, 
01706                                                 endwavelength, dispersion, 0,
01707                                                 NULL);
01708             rect_nflat = mos_spatial_calibration(norm_flat, slits, polytraces, 
01709                                                  reference, startwavelength, 
01710                                                  endwavelength, dispersion, 0,
01711                                                  NULL);
01712 
01713 
01714             if (dfs_save_image(frameset, master_flat, master_screen_flat_tag,
01715                                save_header, parlist, recipe, version))
01716                 fors_pmos_calib_exit(NULL);
01717 
01718 
01719             if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag,
01720                                save_header, parlist, recipe, version))
01721                 fors_pmos_calib_exit(NULL);
01722 
01723             cpl_image_delete(norm_flat); norm_flat = NULL;
01724             cpl_propertylist_delete(save_header); save_header = NULL;
01725 
01726         }
01727 
01728 
01729         /*
01730          * Final wavelength calibration of spectra having their curvature
01731          * removed
01732          */
01733 
01734         cpl_msg_indent_less();
01735         cpl_msg_info(recipe, "Perform final wavelength calibration...");
01736         cpl_msg_indent_more();
01737 
01738         nx = cpl_image_get_size_x(spatial);
01739         ny = cpl_image_get_size_y(spatial);
01740 
01741         idscoeff = cpl_table_new(ny);
01742         restable = cpl_table_new(nlines);
01743         rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01744         if (check)
01745             residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01746         fiterror = cpl_calloc(ny, sizeof(double));
01747         fitlines = cpl_calloc(ny, sizeof(int));
01748 
01749         rectified = mos_wavelength_calibration_final(spatial, slits, lines, 
01750                                                      dispersion, peakdetection,
01751                                                      wradius, wdegree, wreject,
01752                                                      reference,
01753                                                      &startwavelength, 
01754                                                      &endwavelength, fitlines, 
01755                                                      fiterror, idscoeff,
01756                                                      rainbow, 
01757                                                      residual, restable);
01758 
01759         if (rectified == NULL)
01760             fors_pmos_calib_exit("Wavelength calibration failure.");
01761 
01762         if (!j) {
01763             if(dfs_save_image_null(frameset, parlist, disp_residuals_table_tag,
01764                                    recipe, version)) {
01765                 fors_pmos_calib_exit(NULL);
01766             }
01767         }
01768 
01769         header = dfs_load_header(frameset, arc_tag, 0);
01770 
01771         for (k = 0; k < j; k ++) {
01772             cpl_propertylist_delete(header);
01773             header = dfs_load_header(frameset, NULL, 0);
01774         }
01775 
01776         if (dfs_save_table_ext(restable, disp_residuals_table_tag, header)) {
01777             fors_pmos_calib_exit(NULL);
01778         }
01779 
01780         cpl_propertylist_delete(header);
01781 
01782         cpl_table_delete(restable); restable = NULL;
01783 
01784         cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
01785         cpl_table_set_column_unit(idscoeff, "error", "pixel");
01786         cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
01787 
01788         for (i = 0; i < ny; i++)
01789             if (!cpl_table_is_valid(idscoeff, "c0", i))
01790                 cpl_table_set_invalid(idscoeff, "error", i);
01791 
01792         delta = mos_map_pixel(idscoeff, reference, startwavelength,
01793                               endwavelength, dispersion, 2);
01794 
01795         header = dfs_load_header(frameset, arc_tag, 0);
01796 
01797         for (k = 0; k < j; k ++) {
01798             cpl_propertylist_delete(header);
01799             header = dfs_load_header(frameset, NULL, 0);
01800         }
01801 
01802         cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01803         cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01804         cpl_propertylist_update_double(header, "CRVAL1",
01805                                        startwavelength + dispersion/2);
01806         cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01807         /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01808            cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01809         cpl_propertylist_update_double(header, "CD1_1", dispersion);
01810         cpl_propertylist_update_double(header, "CD1_2", 0.0);
01811         cpl_propertylist_update_double(header, "CD2_1", 0.0);
01812         cpl_propertylist_update_double(header, "CD2_2", 1.0);
01813         cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01814         cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01815 
01816         if (!j) {
01817             if(dfs_save_image_null(frameset, parlist, delta_image_tag,
01818                                    recipe, version)) {
01819                 fors_pmos_calib_exit(NULL);
01820             }
01821         }
01822 
01823         if (dfs_save_image_ext(delta, delta_image_tag, header)) {
01824             fors_pmos_calib_exit(NULL);
01825         }
01826 
01827         cpl_image_delete(delta); delta = NULL;
01828         cpl_propertylist_delete(header); header = NULL;
01829 
01830         mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 
01831                                        dispersion, 6, 0);
01832 
01833         cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
01834 
01835         mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01836         mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error");
01837 
01838         cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 
01839                      mean_rms, mean_rms * dispersion);
01840 
01841         restab = mos_resolution_table(rectified, startwavelength, dispersion, 
01842                                       60000, lines);
01843 
01844         if (restab) {
01845             cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 
01846                          cpl_table_get_column_mean(restab, "resolution"));
01847             cpl_msg_info(recipe,
01848                   "Mean reference lines FWHM: %.2f +/- %.2f pixel",
01849                   cpl_table_get_column_mean(restab, "fwhm") / dispersion,
01850                   cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
01851 
01852             cpl_table_duplicate_column(restab, "dlambda", 
01853                                        restab, "fwhm");
01854             cpl_table_multiply_scalar(restab, "dlambda", dispersion);
01855             cpl_table_duplicate_column(restab, "dlambda_rms", 
01856                                        restab, "fwhm_rms");
01857             cpl_table_multiply_scalar(restab, "dlambda_rms", dispersion);
01858 
01859             if (qc) {
01860 
01861                 header = dfs_load_header(frameset, arc_tag, 0);
01862 
01863                 for (k = 0; k < j; k ++) {
01864                     cpl_propertylist_delete(header);
01865                     header = dfs_load_header(frameset, NULL, 0);
01866                 }
01867 
01868                 if (header == NULL)
01869                     fors_pmos_calib_exit("Cannot reload arc lamp header");
01870 
01871                 qclist = cpl_propertylist_new();
01872 
01873                 fors_qc_start_group(qclist, "2.0", instrume);
01874 
01875 
01876                 /*
01877                  * QC1 group header
01878                  */
01879 
01880                 if (fors_qc_write_string("PRO.CATG", spectral_resolution_tag,
01881                                          "Product category", instrume))
01882                     fors_pmos_calib_exit("Cannot write product category to "
01883                                          "QC log file");
01884 
01885                 if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
01886                                            "DPR type", instrume))
01887                     fors_pmos_calib_exit("Missing keyword DPR TYPE in arc "
01888                                          "lamp header");
01889 
01890                 if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
01891                                            "Template", instrume))
01892                     fors_pmos_calib_exit("Missing keyword TPL ID in arc "
01893                                          "lamp header");
01894 
01895                 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 NAME", NULL,
01896                                            "Grism name", instrume))
01897                     fors_pmos_calib_exit("Missing keyword INS GRIS1 NAME in "
01898                                          "arc lamp header");
01899 
01900                 if (fors_qc_keyword_to_paf(header, "ESO INS GRIS1 ID", NULL,
01901                                            "Grism identifier", instrume))
01902                     fors_pmos_calib_exit("Missing keyword INS GRIS1 ID in arc "
01903                                          "lamp header");
01904 
01905                 if (cpl_propertylist_has(header, "ESO INS FILT1 NAME"))
01906                     fors_qc_keyword_to_paf(header, "ESO INS FILT1 NAME", NULL,
01907                                            "Filter name", instrume);
01908 
01909                 if (fors_qc_keyword_to_paf(header, "ESO INS COLL NAME", NULL,
01910                                            "Collimator name", instrume))
01911                     fors_pmos_calib_exit("Missing keyword INS COLL NAME in arc "
01912                                          "lamp header");
01913 
01914                 if (fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
01915                                            "Chip identifier", instrume))
01916                     fors_pmos_calib_exit("Missing keyword DET CHIP1 ID in arc "
01917                                          "lamp header");
01918 
01919                 if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
01920                                            "Archive name of input data", 
01921                                            instrume))
01922                     fors_pmos_calib_exit("Missing keyword ARCFILE in arc "
01923                                          "lamp header");
01924 
01925                 cpl_propertylist_delete(header); header = NULL;
01926 
01927                 pipefile = dfs_generate_filename_tfits(spectral_resolution_tag);
01928                 if (fors_qc_write_string("PIPEFILE", pipefile,
01929                                          "Pipeline product name", instrume))
01930                     fors_pmos_calib_exit("Cannot write PIPEFILE to QC logfile");
01931                 cpl_free(pipefile); pipefile = NULL;
01932 
01933 
01934                 /*
01935                  * QC1 parameters
01936                  */
01937 
01938                 keyname = "QC.PMOS.RESOLUTION";
01939 
01940                 if (fors_qc_write_qc_double(qclist, 
01941                                             cpl_table_get_column_mean(restab,
01942                                             "resolution"),
01943                                             keyname,
01944                                             "Angstrom",
01945                                             "Mean spectral resolution",
01946                                             instrume)) {
01947                     fors_pmos_calib_exit("Cannot write mean spectral "
01948                                          "resolution to QC log file");
01949                 }
01950 
01951                 keyname = "QC.PMOS.RESOLUTION.RMS";
01952 
01953                 if (fors_qc_write_qc_double(qclist, 
01954                                             cpl_table_get_column_stdev(restab, 
01955                                             "resolution"),
01956                                             keyname,
01957                                             "Angstrom", 
01958                                             "Scatter of spectral resolution",
01959                                             instrume)) {
01960                     fors_pmos_calib_exit("Cannot write spectral resolution "
01961                                          "scatter to QC log file");
01962                 }
01963 
01964                 keyname = "QC.PMOS.RESOLUTION.NWAVE";
01965 
01966                 if (fors_qc_write_qc_int(qclist, cpl_table_get_nrow(restab) -
01967                                          cpl_table_count_invalid(restab, 
01968                                                                  "resolution"),
01969                                          keyname,
01970                                          NULL,
01971                                          "Number of examined wavelengths "
01972                                          "for resolution computation",
01973                                          instrume)) {
01974                     fors_pmos_calib_exit("Cannot write number of lines used "
01975                                          "in spectral resolution computation "
01976                                          "to QC log file");
01977                 }
01978 
01979                 keyname = "QC.PMOS.RESOLUTION.MEANRMS";
01980                     
01981                 if (fors_qc_write_qc_double(qclist,
01982                                             cpl_table_get_column_mean(restab,
01983                                             "resolution_rms"),
01984                                             keyname, NULL,
01985                                             "Mean error on spectral "
01986                                             "resolution computation",
01987                                             instrume)) {
01988                     fors_pmos_calib_exit("Cannot write mean error in "
01989                                          "spectral resolution computation "
01990                                          "to QC log file");
01991                 }
01992 
01993                 keyname = "QC.PMOS.RESOLUTION.NLINES";
01994 
01995                 if (fors_qc_write_qc_int(qclist,
01996                                          cpl_table_get_column_mean(restab, 
01997                                                                    "nlines") *
01998                                          cpl_table_get_nrow(restab),
01999                                          keyname, NULL,
02000                                          "Number of lines for spectral "
02001                                          "resolution computation",
02002                                          instrume)) {
02003                     fors_pmos_calib_exit("Cannot write number of examined "
02004                                          "wavelengths in spectral resolution "
02005                                          "computation to QC log file");
02006                 }
02007 
02008                 fors_qc_end_group();
02009 
02010             }
02011 
02012             if (!j) {
02013                 if(dfs_save_image_null(frameset, parlist, 
02014                                        spectral_resolution_tag,
02015                                        recipe, version)) {
02016                     fors_pmos_calib_exit(NULL);
02017                 }
02018             }
02019 
02020             header = dfs_load_header(frameset, arc_tag, 0);
02021 
02022             for (k = 0; k < j; k ++) {
02023                 cpl_propertylist_delete(header);
02024                 header = dfs_load_header(frameset, NULL, 0);
02025             }
02026 
02027             cpl_propertylist_append(header, qclist);
02028 
02029             if (dfs_save_table_ext(restab, spectral_resolution_tag, header)) {
02030                 fors_pmos_calib_exit(NULL);
02031             }
02032 
02033             cpl_table_delete(restab); restab = NULL;
02034             cpl_propertylist_delete(qclist); qclist = NULL;
02035             cpl_propertylist_delete(header); header = NULL;
02036 
02037         }
02038         else
02039             fors_pmos_calib_exit("Cannot compute the spectral "
02040                                  "resolution table");
02041 
02042         if (!j) {
02043             if(dfs_save_image_null(frameset, parlist, disp_coeff_tag,
02044                                    recipe, version)) {
02045                 fors_pmos_calib_exit(NULL);
02046             }
02047         }
02048 
02049         header = dfs_load_header(frameset, arc_tag, 0);
02050 
02051         for (k = 0; k < j; k ++) {
02052             cpl_propertylist_delete(header);
02053             header = dfs_load_header(frameset, NULL, 0);
02054         }
02055 
02056         if (dfs_save_table_ext(idscoeff, disp_coeff_tag, header)) {
02057             fors_pmos_calib_exit(NULL);
02058         }
02059 
02060         cpl_propertylist_delete(header);
02061 
02062         if (!j) {
02063             mapped_flat = mos_wavelength_calibration(rect_flat, reference,
02064                                                      startwavelength, 
02065                                                      endwavelength,
02066                                                      dispersion, idscoeff, 0);
02067 
02068             mapped_nflat = mos_wavelength_calibration(rect_nflat, reference,
02069                                                       startwavelength, 
02070                                                       endwavelength,
02071                                                       dispersion, idscoeff, 0);
02072 
02073             cpl_image_delete(rect_flat); rect_flat = NULL;
02074             cpl_image_delete(rect_nflat); rect_nflat = NULL;
02075         }
02076 
02077         /* Global removed */
02078 
02079         cpl_table_delete(idscoeff); idscoeff = NULL;
02080 
02081         header = dfs_load_header(frameset, arc_tag, 0);
02082 
02083         for (k = 0; k < j; k ++) {
02084             cpl_propertylist_delete(header);
02085             header = dfs_load_header(frameset, NULL, 0);
02086         }
02087 
02088         cpl_propertylist_update_double(header, "CRPIX1", 1.0);
02089         cpl_propertylist_update_double(header, "CRPIX2", 1.0);
02090         cpl_propertylist_update_double(header, "CRVAL1", 
02091                                        startwavelength + dispersion/2);
02092         cpl_propertylist_update_double(header, "CRVAL2", 1.0);
02093         /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02094            cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02095         cpl_propertylist_update_double(header, "CD1_1", dispersion);
02096         cpl_propertylist_update_double(header, "CD1_2", 0.0);
02097         cpl_propertylist_update_double(header, "CD2_1", 0.0);
02098         cpl_propertylist_update_double(header, "CD2_2", 1.0);
02099         cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
02100         cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
02101         cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1);
02102 
02103         if (!j) {
02104             if(dfs_save_image_null(frameset, parlist, reduced_lamp_tag,
02105                                    recipe, version)) {
02106                 fors_pmos_calib_exit(NULL);
02107             }
02108         }
02109 
02110         if (dfs_save_image_ext(rectified, reduced_lamp_tag, header)) {
02111             fors_pmos_calib_exit(NULL);
02112         }
02113 
02114         cpl_image_delete(rectified); rectified = NULL;
02115 
02116         cpl_propertylist_update_int(header, "ESO PRO DATANCOM", nflats);
02117 
02118         if (!j) {
02119             if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag,
02120                                header, parlist, recipe, version))
02121                 fors_pmos_calib_exit(NULL);
02122             cpl_image_delete(mapped_flat); mapped_flat = NULL;
02123 
02124             if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag,
02125                                header, parlist, recipe, version))
02126                 fors_pmos_calib_exit(NULL);
02127             cpl_image_delete(mapped_nflat); mapped_nflat = NULL;
02128         }
02129 
02130         cpl_propertylist_delete(header); header = NULL;
02131 
02132         if (check) {
02133             save_header = dfs_load_header(frameset, arc_tag, 0);
02134             for (k = 0; k < j; k ++) {
02135                 cpl_propertylist_delete(save_header);
02136                 save_header = dfs_load_header(frameset, NULL, 0);
02137             }
02138 
02139             cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
02140             cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
02141             /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
02142             cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
02143             cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
02144             cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
02145             cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
02146             cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
02147             cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
02148 
02149             if (!j) {
02150                 if(dfs_save_image_null(frameset, parlist, disp_residuals_tag,
02151                                        recipe, version)) {
02152                     fors_pmos_calib_exit(NULL);
02153                 }
02154             }
02155 
02156             if (dfs_save_image_ext(residual, disp_residuals_tag, save_header)) {
02157                 fors_pmos_calib_exit(NULL);
02158             }
02159 
02160             cpl_image_delete(residual); residual = NULL;
02161             cpl_propertylist_delete(save_header); save_header = NULL;
02162         }
02163 
02164         wavemap = mos_map_wavelengths(coordinate, rainbow, slits, polytraces, 
02165                                       reference, startwavelength, endwavelength, 
02166                                       dispersion);
02167 
02168         cpl_image_delete(rainbow); rainbow = NULL;
02169 
02170         save_header = dfs_load_header(frameset, arc_tag, 0);
02171 
02172         for (k = 0; k < j; k ++) {
02173             cpl_propertylist_delete(save_header);
02174             save_header = dfs_load_header(frameset, NULL, 0);
02175         }
02176 
02177         if (qc) {
02178             fors_qc_start_group(save_header, "2.0", instrume);
02179 
02180             /*
02181              * QC1 group header
02182              */
02183 
02184             if (fors_qc_write_string("PRO.CATG", wavelength_map_tag,
02185                                      "Product category", instrume))
02186                 fors_pmos_calib_exit("Cannot write product category to "
02187                                      "QC log file");
02188 
02189             if (fors_qc_keyword_to_paf(save_header, "ESO DPR TYPE", NULL,
02190                                        "DPR type", instrume))
02191                 fors_pmos_calib_exit("Missing keyword DPR TYPE in arc "
02192                                      "lamp header");
02193 
02194             if (fors_qc_keyword_to_paf(save_header, "ESO TPL ID", NULL,
02195                                        "Template", instrume))
02196                 fors_pmos_calib_exit("Missing keyword TPL ID in arc "
02197                                      "lamp header");
02198 
02199             if (fors_qc_keyword_to_paf(save_header, "ESO INS GRIS1 NAME", NULL,
02200                                        "Grism name", instrume))
02201                 fors_pmos_calib_exit("Missing keyword INS GRIS1 NAME in arc "
02202                                      "lamp header");
02203 
02204             if (fors_qc_keyword_to_paf(save_header, "ESO INS GRIS1 ID", NULL,
02205                                        "Grism identifier", instrume))
02206                 fors_pmos_calib_exit("Missing keyword INS GRIS1 ID in arc "
02207                                      "lamp header");
02208 
02209             if (cpl_propertylist_has(save_header, "ESO INS FILT1 NAME"))
02210                 fors_qc_keyword_to_paf(save_header, "ESO INS FILT1 NAME", NULL,
02211                                        "Filter name", instrume);
02212 
02213             if (fors_qc_keyword_to_paf(save_header, "ESO INS COLL NAME", NULL,
02214                                        "Collimator name", instrume))
02215                 fors_pmos_calib_exit("Missing keyword INS COLL NAME in arc "
02216                                      "lamp header");
02217 
02218             if (fors_qc_keyword_to_paf(save_header, "ESO DET CHIP1 ID", NULL,
02219                                        "Chip identifier", instrume))
02220                 fors_pmos_calib_exit("Missing keyword DET CHIP1 ID in arc "
02221                                      "lamp header");
02222 
02223             if (fors_qc_keyword_to_paf(save_header, "ESO DET WIN1 BINX", NULL,
02224                                        "Binning factor along X", instrume))
02225                 fors_pmos_calib_exit("Missing keyword ESO DET WIN1 BINX "
02226                                      "in frame header");
02227 
02228             if (fors_qc_keyword_to_paf(save_header, "ESO DET WIN1 BINY", NULL,
02229                                        "Binning factor along Y", instrume))
02230                 fors_pmos_calib_exit("Missing keyword ESO DET WIN1 BINY "
02231                                      "in frame header");
02232 
02233             if (fors_qc_keyword_to_paf(save_header, "ARCFILE", NULL,
02234                                        "Archive name of input data",
02235                                        instrume))
02236                 fors_pmos_calib_exit("Missing keyword ARCFILE in arc "
02237                                      "lamp header");
02238 
02239             pipefile = dfs_generate_filename(wavelength_map_tag);
02240             if (fors_qc_write_string("PIPEFILE", pipefile,
02241                                      "Pipeline product name", instrume))
02242                 fors_pmos_calib_exit("Cannot write PIPEFILE to QC log file");
02243             cpl_free(pipefile); pipefile = NULL;
02244 
02245 
02246             /*
02247              * QC1 parameters
02248              */
02249 
02250             if (fors_qc_write_qc_double(save_header,
02251                                         mean_rms,
02252                                         "QC.WAVE.ACCURACY",
02253                                         "pixel",
02254                                         "Mean accuracy of wavecalib model",
02255                                         instrume)) {
02256                 fors_pmos_calib_exit("Cannot write mean wavelength calibration "
02257                                      "accuracy to QC log file");
02258             }
02259 
02260 
02261             if (fors_qc_write_qc_double(save_header,
02262                                         mean_rms_err,
02263                                         "QC.WAVE.ACCURACY.ERROR",
02264                                         "pixel",
02265                                         "Error on accuracy of wavecalib model",
02266                                         instrume)) {
02267                 fors_pmos_calib_exit("Cannot write error on wavelength "
02268                                      "calibration accuracy to QC log file");
02269             }
02270 
02271             if (same_offset && fabs(mxpos) < 0.05) { 
02272                                              /* Only if same offset is 0.0 */
02273 
02274                 data = cpl_image_get_data(wavemap);
02275 
02276                 if (fors_qc_write_qc_double(save_header,
02277                                            data[nx/2 + ccd_ysize*nx/2],
02278                                            "QC.PMOS.CENTRAL.WAVELENGTH",
02279                                            "Angstrom",
02280                                            "Wavelength at CCD center",
02281                                            instrume)) {
02282                     fors_pmos_calib_exit("Cannot write central wavelength "
02283                                          "to QC log file");
02284                 }
02285             }
02286 
02287             fors_qc_end_group();
02288 
02289         }
02290 
02291         if (!j) {
02292             if(dfs_save_image_null(frameset, parlist, wavelength_map_tag,
02293                                    recipe, version)) {
02294                 fors_pmos_calib_exit(NULL);
02295             }
02296         }
02297 
02298         if (dfs_save_image_ext(wavemap, wavelength_map_tag, save_header)) {
02299             fors_pmos_calib_exit(NULL);
02300         }
02301 
02302         cpl_image_delete(wavemap); wavemap = NULL;
02303 
02304         cpl_propertylist_erase_regexp(save_header, "^ESO QC ", 0);
02305 
02306         cpl_propertylist_delete(save_header); save_header = NULL;
02307 
02308         cpl_msg_indent_less();
02309 
02310     }
02311 
02312     if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header,
02313                        parlist, recipe, version))
02314         fors_pmos_calib_exit(NULL);
02315 
02316     cpl_image_delete(coordinate); coordinate = NULL;
02317     cpl_propertylist_delete(save_header); save_header = NULL;
02318 
02319     header = NULL;
02320 
02321     if (qc) {
02322 
02323         double maxpos, maxneg, maxcurve, maxslope;
02324 
02325         header = dfs_load_header(frameset, arc_tag, 0);
02326 
02327         fors_qc_start_group(header, "2.0", instrume);
02328 
02329         /*
02330          * QC1 group header
02331          */
02332 
02333         if (fors_qc_write_string("PRO.CATG", curv_coeff_tag,
02334                                 "Product category", instrume))
02335             fors_pmos_calib_exit("Cannot write product category to "
02336                                  "QC log file");
02337 
02338         if (fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
02339                                   "DPR type", instrume))
02340             fors_pmos_calib_exit("Missing keyword DPR TYPE in arc "
02341                                  "lamp header");
02342 
02343         if (fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
02344                                   "Template", instrume))
02345             fors_pmos_calib_exit("Missing keyword TPL ID in arc "
02346                                  "lamp header");
02347         if (fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
02348                                   "Archive name of input data",
02349                                   instrume))
02350             fors_pmos_calib_exit("Missing keyword ARCFILE in arc "
02351                                  "lamp header");
02352 
02353         pipefile = dfs_generate_filename(curv_coeff_tag);
02354         if (fors_qc_write_string("PIPEFILE", pipefile,
02355                                 "Pipeline product name", instrume))
02356             fors_pmos_calib_exit("Cannot write PIPEFILE to QC log file");
02357         cpl_free(pipefile); pipefile = NULL;
02358 
02359         /*
02360          * QC1 parameters
02361          */
02362 
02363         maxpos = fabs(cpl_table_get_column_max(polytraces, "c2"));
02364         maxneg = fabs(cpl_table_get_column_min(polytraces, "c2"));
02365         maxcurve = maxpos > maxneg ? maxpos : maxneg;
02366         if (fors_qc_write_qc_double(header,
02367                                    maxcurve,
02368                                    "QC.TRACE.MAX.CURVATURE",
02369                                    "Y pixel / X pixel ^2",
02370                                    "Max observed curvature in spectral tracing",
02371                                    instrume)) {
02372             fors_pmos_calib_exit("Cannot write max observed curvature in "
02373                                  "spectral tracing to QC log file");
02374         }
02375 
02376         maxpos = fabs(cpl_table_get_column_max(polytraces, "c1"));
02377         maxneg = fabs(cpl_table_get_column_min(polytraces, "c1"));
02378         maxslope = maxpos > maxneg ? maxpos : maxneg;
02379 
02380         if (fors_qc_write_qc_double(header,
02381                                    maxslope,
02382                                    "QC.TRACE.MAX.SLOPE",
02383                                    "Y pixel / X pixel",
02384                                    "Max observed slope in spectral tracing",
02385                                    instrume)) {
02386             fors_pmos_calib_exit("Cannot write max observed slope in spectral "
02387                                  "tracing to QC log file");
02388         }
02389 
02390         fors_qc_end_group();
02391     }
02392 
02393     if (dfs_save_table(frameset, polytraces, curv_coeff_tag, header,
02394                        parlist, recipe, version)) {
02395         fors_pmos_calib_exit(NULL);
02396     }
02397 
02398     cpl_propertylist_delete(header); header = NULL;
02399     cpl_table_delete(polytraces); polytraces = NULL;
02400 
02401     /* FIXLANDER It was slit_ident == 0 and 
02402        it was in a different place above in the code */
02403 
02404     if (same_offset) {
02405         cpl_table *globaltbl;
02406         cpl_table *slitpos;
02407         double    *l_ytop;
02408         int       *l_id;
02409         int        npairs;
02410         double    *ytop   = cpl_table_get_data_double(slits, "ytop");
02411         double    *ybot   = cpl_table_get_data_double(slits, "ybottom");
02412         int        k;
02413 // int    *p_id;
02414 
02415         /* Just in case it has been modified */
02416         nslits = cpl_table_get_nrow(slits);
02417 
02418         cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT);
02419 // p_id   = cpl_table_get_data_int(slits, "pair_id");
02420 
02421         if (ccd_ysize == 400 || ccd_ysize == 500) {
02422             
02423             /*
02424              * Special case with old FORS1 chip
02425              */
02426 
02427             l_ytop = cpl_malloc(sizeof(double));
02428             l_ytop[0] = 255.0;
02429             l_id = cpl_malloc(sizeof(double));
02430             l_id[0] = 10;
02431             npairs = 1;
02432         }
02433         else {
02434             globaltbl = dfs_load_table(frameset, master_distortion_tag, 1);
02435             slitpos = mos_build_slit_location(globaltbl, maskslits, ccd_ysize);
02436             l_ytop = cpl_table_get_data_double(slitpos, "ytop");
02437             l_id   = cpl_table_get_data_int(slitpos, "slit_id");
02438             npairs = cpl_table_get_nrow(slitpos);
02439             if (rebin_dist != rebin) {
02440                 float rescale = (float)rebin_dist / rebin;
02441                 for (i = 0; i < npairs; i++) {
02442                    l_ytop[i] *= rescale;
02443                 }
02444             }
02445         }
02446 
02447         for (k = 0; k < npairs; k++) {
02448             int h;
02449 
02450             for (h = 0; h < nslits; h++) {
02451 
02452                 if (l_ytop[k] < ytop[h] && l_ytop[k] > ybot[h]) {
02453                     if (h + 1 < nslits) {
02454                         cpl_table_set_int(slits, "pair_id", h, l_id[k]);
02455                         cpl_table_set_int(slits, "pair_id", h + 1, l_id[k]);
02456                     }
02457                 }
02458             }
02459         }
02460 
02461 /* %%% */
02462 
02463         cpl_table_fill_invalid_int(slits, "pair_id", -1);
02464 
02465         if (ccd_ysize == 400 || ccd_ysize == 500) {
02466             cpl_free(l_ytop);
02467             cpl_free(l_id);
02468         }
02469         else {
02470             cpl_table_delete(slitpos);   slitpos   = NULL;
02471             cpl_table_delete(globaltbl); globaltbl = NULL;
02472     
02473             cpl_table_delete(maskslits); maskslits = NULL;
02474         }
02475     }
02476 
02477     if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
02478                        parlist, recipe, version)) {
02479         fors_pmos_calib_exit(NULL);
02480     }
02481 
02482     cpl_table_delete(slits); slits = NULL;
02483 
02484     cpl_image_delete(spatial); spatial = NULL;
02485 
02486     cpl_free(instrume); instrume = NULL;
02487 
02488     cpl_table_delete(overscans); overscans = NULL;
02489     cpl_image_delete(master_bias); master_bias = NULL;
02490     cpl_image_delete(master_flat); master_flat = NULL;
02491 
02492     cpl_table_delete(wavelengths); wavelengths = NULL;
02493     cpl_vector_delete(lines); lines = NULL;
02494 
02495     if (cpl_error_get_code()) {
02496         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
02497         fors_pmos_calib_exit(NULL);
02498     }
02499 
02500     return 0;
02501 }

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