fors_pmos_calib.c

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

Generated on 12 Feb 2016 for FORS Pipeline Reference Manual by  doxygen 1.6.1