fors_pmos_extract.c

00001 /* $Id: fors_pmos_extract.c,v 1.6 2010/09/14 07:38:16 cizzo Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cizzo $
00023  * $Date: 2010/09/14 07:38:16 $
00024  * $Revision: 1.6 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <string.h>
00034 #include <ctype.h>
00035 #include <assert.h>
00036 
00037 #include <cpl.h>
00038 #include <moses.h>
00039 #include <fors_dfs.h>
00040 #include <fors_utils.h>
00041 #include <fors_qc.h>
00042 
00043 static int fors_pmos_extract_create(cpl_plugin *);
00044 static int fors_pmos_extract_exec(cpl_plugin *);
00045 static int fors_pmos_extract_destroy(cpl_plugin *);
00046 static int fors_pmos_extract(cpl_parameterlist *, cpl_frameset *);
00047 
00048 static float * fors_check_angles(cpl_frameset *, int, const char *, int *);
00049 static int
00050 fors_find_angle_pos(float * angles, int nangles, float angle);
00051 
00052 static char fors_pmos_extract_description[] =
00053 "This recipe is used to reduce scientific spectra using the extraction\n"
00054 "mask and the products created by the recipe fors_mpol_calib. The spectra\n"
00055 "are bias subtracted, flat fielded (if a normalised flat field is specified)\n"
00056 "and remapped eliminating the optical distortions. The wavelength calibration\n"
00057 "can be optionally upgraded using a number of sky lines: if no sky lines\n"
00058 "catalog of wavelengths is specified, an internal one is used instead.\n"
00059 "If the alignment to the sky lines is performed, the input dispersion\n"
00060 "coefficients table is upgraded and saved to disk, and a new CCD wavelengths\n"
00061 "map is created.\n"
00062 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n"
00063 "depending on the instrument mode, and in particular on the grism used)\n"
00064 "may also be specified: this table contains a default recipe parameter\n" 
00065 "setting to control the way spectra are extracted for a specific instrument\n"
00066 "mode, as it is used for automatic run of the pipeline on Paranal and in\n" 
00067 "Garching. If this table is specified, it will modify the default recipe\n" 
00068 "parameter setting, with the exception of those parameters which have been\n" 
00069 "explicitly modifyed on the command line. If a grism table is not specified,\n"
00070 "the input recipe parameters values will always be read from the command\n" 
00071 "line, or from an esorex configuration file if present, or from their\n" 
00072 "generic default values (that are rarely meaningful).\n" 
00073 "Either a scientific or a standard star exposure can be specified in input.\n"
00074 "The acronym SCI on products should be read STD in case of standard stars\n"
00075 "observations.\n\n"
00076 "Input files:\n\n"
00077 "  DO category:               Type:       Explanation:         Required:\n"
00078 "  SCIENCE_PMOS                  Raw         Scientific exposure     Y\n"
00079 "  or STANDARD_PMOS              Raw         Standard star exposure  Y\n"
00080 "  MASTER_BIAS                   Calib       Master bias             Y\n"
00081 "  GRISM_TABLE                   Calib       Grism table             .\n"
00082 "  MASTER_SKYLINECAT             Calib       Sky lines catalog       .\n"
00083 "\n"
00084 "  MASTER_NORM_FLAT_PMOS         Calib       Normalised flat field   .\n"
00085 "  DISP_COEFF_PMOS               Calib       Inverse dispersion      Y\n"
00086 "  CURV_COEFF_PMOS               Calib       Spectral curvature      Y\n"
00087 "  SLIT_LOCATION_PMOS            Calib       Slits positions table   Y\n"
00088 "  RETARDER_WAVEPLATE_CHROMATISM Calib       Chromatism correction   .\n"
00089 "\n"
00090 "Output files:\n\n"
00091 "  DO category:               Data type:  Explanation:\n"
00092 "  REDUCED_SCI_PMOS             FITS image  Extracted scientific spectra\n"
00093 "  REDUCED_SKY_SCI_PMOS         FITS image  Extracted sky spectra\n"
00094 "  REDUCED_ERROR_SCI_PMOS       FITS image  Errors on extracted spectra\n"
00095 "  REDUCED_SCI_X_PMOS           FITS image  X Stokes parameter (and L)\n"
00096 "  REDUCED_ERROR_X_PMOS         FITS image  Error on X Stokes parameter\n"
00097 "  REDUCED_NUL_X_PMOS           FITS image  Null parameter for X\n"
00098 "  REDUCED_POL_ANGLE_PMOS       FITS image  Direction of linear polarization\n"
00099 "  REDUCED_POL_ANGLE_ERROR_PMOS FITS image  Error on polarization direction\n"
00100 "  UNMAPPED_SCI_PMOS            FITS image  Sky subtracted scientific spectra\n"
00101 "  MAPPED_SCI_PMOS              FITS image  Rectified scientific spectra\n"
00102 "  MAPPED_ALL_SCI_PMOS          FITS image  Rectified science spectra with sky\n"
00103 "  MAPPED_SKY_SCI_PMOS          FITS image  Rectified sky spectra\n"
00104 "  UNMAPPED_SKY_SCI_PMOS        FITS image  Sky on CCD\n"
00105 "  GLOBAL_SKY_SPECTRUM_PMOS     FITS table  Global sky spectrum\n"
00106 "  OBJECT_TABLE_SCI_PMOS        FITS table  Positions of detected objects\n"
00107 "  OBJECT_TABLE_POL_SCI_PMOS    FITS table  Positions of real objects\n"
00108 "\n"
00109 "  Only if the sky-alignment of the wavelength solution is requested:\n"
00110 "  DISP_COEFF_SCI_PMOS          FITS table  Upgraded dispersion coefficients\n"
00111 "  WAVELENGTH_MAP_SCI_PMOS      FITS image  Upgraded wavelength map\n\n";
00112 
00113 #define fors_pmos_extract_exit(message)            \
00114 {                                             \
00115 if (message) cpl_msg_error(recipe, message);  \
00116 cpl_free(instrume);                           \
00117 cpl_image_delete(dummy);                      \
00118 cpl_image_delete(mapped_sky);                 \
00119 cpl_image_delete(mapped_cleaned);             \
00120 cpl_image_delete(skymap);                     \
00121 cpl_image_delete(smapped);                    \
00122 cpl_table_delete(offsets);                    \
00123 cpl_table_delete(sky);                        \
00124 cpl_image_delete(bias);                       \
00125 cpl_image_delete(spectra);                    \
00126 cpl_image_delete(coordinate);                 \
00127 cpl_image_delete(norm_flat);                  \
00128 cpl_image_delete(rainbow);                    \
00129 cpl_image_delete(rectified);                  \
00130 cpl_image_delete(wavemap);                    \
00131 cpl_propertylist_delete(header);              \
00132 cpl_propertylist_delete(save_header);         \
00133 cpl_table_delete(grism_table);                \
00134 cpl_table_delete(idscoeff);                   \
00135 cpl_table_delete(maskslits);                  \
00136 cpl_table_delete(overscans);                  \
00137 cpl_table_delete(polytraces);                 \
00138 cpl_table_delete(wavelengths);                \
00139 cpl_vector_delete(lines);                     \
00140 cpl_msg_indent_less();                        \
00141 return -1;                                    \
00142 }
00143 
00144 
00145 #define fors_pmos_extract_exit_memcheck(message)   \
00146 {                                             \
00147 if (message) cpl_msg_info(recipe, message);   \
00148 cpl_free(instrume);                           \
00149 cpl_image_delete(dummy);                      \
00150 cpl_image_delete(mapped_cleaned);             \
00151 cpl_image_delete(mapped_sky);                 \
00152 cpl_image_delete(skymap);                     \
00153 cpl_image_delete(smapped);                    \
00154 cpl_table_delete(offsets);                    \
00155 cpl_table_delete(sky);                        \
00156 cpl_image_delete(bias);                       \
00157 cpl_image_delete(spectra);                    \
00158 cpl_image_delete(coordinate);                 \
00159 cpl_image_delete(norm_flat);                  \
00160 cpl_image_delete(rainbow);                    \
00161 cpl_image_delete(rectified);                  \
00162 cpl_image_delete(wavemap);                    \
00163 cpl_propertylist_delete(header);              \
00164 cpl_propertylist_delete(save_header);         \
00165 cpl_table_delete(grism_table);                \
00166 cpl_table_delete(idscoeff);                   \
00167 cpl_table_delete(maskslits);                  \
00168 cpl_table_delete(overscans);                  \
00169 cpl_table_delete(polytraces);                 \
00170 cpl_table_delete(wavelengths);                \
00171 cpl_vector_delete(lines);                     \
00172 cpl_msg_indent_less();                        \
00173 return 0;                                     \
00174 }
00175 
00176 
00188 int cpl_plugin_get_info(cpl_pluginlist *list)
00189 {
00190     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00191     cpl_plugin *plugin = &recipe->interface;
00192 
00193     cpl_plugin_init(plugin,
00194                     CPL_PLUGIN_API,
00195                     FORS_BINARY_VERSION,
00196                     CPL_PLUGIN_TYPE_RECIPE,
00197                     "fors_pmos_extract",
00198                     "Extraction of scientific spectra",
00199                     fors_pmos_extract_description,
00200                     "Carlo Izzo",
00201                     PACKAGE_BUGREPORT,
00202     "This file is currently part of the FORS Instrument Pipeline\n"
00203     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00204     "This program is free software; you can redistribute it and/or modify\n"
00205     "it under the terms of the GNU General Public License as published by\n"
00206     "the Free Software Foundation; either version 2 of the License, or\n"
00207     "(at your option) any later version.\n\n"
00208     "This program is distributed in the hope that it will be useful,\n"
00209     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00210     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00211     "GNU General Public License for more details.\n\n"
00212     "You should have received a copy of the GNU General Public License\n"
00213     "along with this program; if not, write to the Free Software Foundation,\n"
00214     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00215                     fors_pmos_extract_create,
00216                     fors_pmos_extract_exec,
00217                     fors_pmos_extract_destroy);
00218 
00219     cpl_pluginlist_append(list, plugin);
00220     
00221     return 0;
00222 }
00223 
00224 
00235 static int fors_pmos_extract_create(cpl_plugin *plugin)
00236 {
00237     cpl_recipe    *recipe;
00238     cpl_parameter *p;
00239 
00240 
00241     /* 
00242      * Check that the plugin is part of a valid recipe 
00243      */
00244 
00245     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00246         recipe = (cpl_recipe *)plugin;
00247     else 
00248         return -1;
00249 
00250     /* 
00251      * Create the parameters list in the cpl_recipe object 
00252      */
00253 
00254     recipe->parameters = cpl_parameterlist_new(); 
00255 
00256 
00257     /*
00258      * Dispersion
00259      */
00260 
00261     p = cpl_parameter_new_value("fors.fors_pmos_extract.dispersion",
00262                                 CPL_TYPE_DOUBLE,
00263                                 "Resampling step (Angstrom/pixel)",
00264                                 "fors.fors_pmos_extract",
00265                                 0.0);
00266     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00267     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00268     cpl_parameterlist_append(recipe->parameters, p);
00269 
00270     /*
00271      * Sky lines alignment
00272      */
00273 
00274     p = cpl_parameter_new_value("fors.fors_pmos_extract.skyalign",
00275                                 CPL_TYPE_INT,
00276                                 "Polynomial order for sky lines alignment, "
00277                                 "or -1 to avoid alignment",
00278                                 "fors.fors_pmos_extract",
00279                                 0);
00280     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
00281     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00282     cpl_parameterlist_append(recipe->parameters, p);
00283 
00284     /*
00285      * Line catalog table column containing the sky reference wavelengths
00286      */
00287 
00288     p = cpl_parameter_new_value("fors.fors_pmos_extract.wcolumn",
00289                                 CPL_TYPE_STRING,
00290                                 "Name of sky line catalog table column "
00291                                 "with wavelengths",
00292                                 "fors.fors_pmos_extract",
00293                                 "WLEN");
00294     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00295     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00296     cpl_parameterlist_append(recipe->parameters, p);
00297 
00298     /*
00299      * Start wavelength for spectral extraction
00300      */
00301 
00302     p = cpl_parameter_new_value("fors.fors_pmos_extract.startwavelength",
00303                                 CPL_TYPE_DOUBLE,
00304                                 "Start wavelength in spectral extraction",
00305                                 "fors.fors_pmos_extract",
00306                                 0.0);
00307     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00308     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00309     cpl_parameterlist_append(recipe->parameters, p);
00310 
00311     /*
00312      * End wavelength for spectral extraction
00313      */
00314 
00315     p = cpl_parameter_new_value("fors.fors_pmos_extract.endwavelength",
00316                                 CPL_TYPE_DOUBLE,
00317                                 "End wavelength in spectral extraction",
00318                                 "fors.fors_pmos_extract",
00319                                 0.0);
00320     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00321     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00322     cpl_parameterlist_append(recipe->parameters, p);
00323 
00324     /*
00325      * Flux conservation
00326      */
00327 
00328     p = cpl_parameter_new_value("fors.fors_pmos_extract.flux",
00329                                 CPL_TYPE_BOOL,
00330                                 "Apply flux conservation",
00331                                 "fors.fors_pmos_extract",
00332                                 TRUE);
00333     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00334     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00335     cpl_parameterlist_append(recipe->parameters, p);
00336 
00337     /*
00338      * Apply flat field
00339      */
00340 
00341     p = cpl_parameter_new_value("fors.fors_pmos_extract.flatfield",
00342                                 CPL_TYPE_BOOL,
00343                                 "Apply flat field",
00344                                 "fors.fors_pmos_extract",
00345                                 FALSE);
00346     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield");
00347     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00348     cpl_parameterlist_append(recipe->parameters, p);
00349 
00350     /*
00351      * Global sky subtraction
00352      */
00353 
00354     p = cpl_parameter_new_value("fors.fors_pmos_extract.skyglobal",
00355                                 CPL_TYPE_BOOL,
00356                                 "Subtract global sky spectrum from CCD",
00357                                 "fors.fors_pmos_extract",
00358                                 FALSE);
00359     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyglobal");
00360     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00361     cpl_parameterlist_append(recipe->parameters, p);
00362 
00363     p = cpl_parameter_new_value("fors.fors_pmos_extract.skymedian",
00364                                 CPL_TYPE_BOOL,
00365                                 "Sky subtraction from extracted slit spectra",
00366                                 "fors.fors_pmos_extract",
00367                                 FALSE);
00368     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian");
00369     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00370     cpl_parameterlist_append(recipe->parameters, p);
00371 
00372     /*
00373      * Local sky subtraction on CCD spectra
00374      */
00375 
00376     p = cpl_parameter_new_value("fors.fors_pmos_extract.skylocal",
00377                                 CPL_TYPE_BOOL,
00378                                 "Sky subtraction from CCD slit spectra",
00379                                 "fors.fors_pmos_extract",
00380                                 TRUE);
00381     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal");
00382     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00383     cpl_parameterlist_append(recipe->parameters, p);
00384 
00385     /*
00386      * Cosmic rays removal
00387      */
00388 
00389     p = cpl_parameter_new_value("fors.fors_pmos_extract.cosmics",
00390                                 CPL_TYPE_BOOL,
00391                                 "Eliminate cosmic rays hits (only if global "
00392                                 "sky subtraction is also requested)",
00393                                 "fors.fors_pmos_extract",
00394                                 FALSE);
00395     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics");
00396     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00397     cpl_parameterlist_append(recipe->parameters, p);
00398 
00399     /*
00400      * Slit margin
00401      */
00402 
00403     p = cpl_parameter_new_value("fors.fors_pmos_extract.slit_margin",
00404                                 CPL_TYPE_INT,
00405                                 "Number of pixels to exclude at each slit "
00406                                 "in object detection and extraction",
00407                                 "fors.fors_pmos_extract",
00408                                 3);
00409     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin");
00410     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00411     cpl_parameterlist_append(recipe->parameters, p);
00412 
00413     /*
00414      * Extraction radius
00415      */
00416 
00417     p = cpl_parameter_new_value("fors.fors_pmos_extract.ext_radius",
00418                                 CPL_TYPE_INT,
00419                                 "Maximum extraction radius for detected "
00420                                 "objects (pixel)",
00421                                 "fors.fors_pmos_extract",
00422                                 6);
00423     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius");
00424     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00425     cpl_parameterlist_append(recipe->parameters, p);
00426 
00427     /*
00428      * Contamination radius
00429      */
00430 
00431     p = cpl_parameter_new_value("fors.fors_pmos_extract.cont_radius",
00432                                 CPL_TYPE_INT,
00433                                 "Minimum distance at which two objects "
00434                                 "of equal luminosity do not contaminate "
00435                                 "each other (pixel)",
00436                                 "fors.fors_pmos_extract",
00437                                 0);
00438     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius");
00439     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00440     cpl_parameterlist_append(recipe->parameters, p);
00441 
00442     /*
00443      * Object extraction method
00444      */
00445 
00446     p = cpl_parameter_new_value("fors.fors_pmos_extract.ext_mode",
00447                                 CPL_TYPE_INT,
00448                                 "Object extraction method: 0 = aperture, "
00449                                 "1 = Horne optimal extraction",
00450                                 "fors.fors_pmos_extract",
00451                                 1);
00452     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode");
00453     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00454     cpl_parameterlist_append(recipe->parameters, p);
00455 
00456     /*
00457      * Normalise output by exposure time
00458      */
00459 
00460     p = cpl_parameter_new_value("fors.fors_pmos_extract.time_normalise",
00461                                 CPL_TYPE_BOOL,
00462                                 "Normalise output spectra by the exposure time",
00463                                 "fors.fors_pmos_extract",
00464                                 TRUE);
00465     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise");
00466     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00467     cpl_parameterlist_append(recipe->parameters, p);
00468 
00469     /*
00470      * Apply chromatism correction to polarization angle
00471      */
00472 
00473     p = cpl_parameter_new_value("fors.fors_pmos_extract.chromatism",
00474                                 CPL_TYPE_BOOL,
00475                                 "Chromatism correction to polarization angles",
00476                                 "fors.fors_pmos_extract",
00477                                 TRUE);
00478     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "chromatism");
00479     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00480     cpl_parameterlist_append(recipe->parameters, p);
00481 
00482     /*
00483      * Create check products
00484      */
00485 
00486     p = cpl_parameter_new_value("fors.fors_pmos_extract.check",
00487                                 CPL_TYPE_BOOL,
00488                                 "Create intermediate products",
00489                                 "fors.fors_pmos_extract",
00490                                 FALSE);
00491     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check");
00492     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00493     cpl_parameterlist_append(recipe->parameters, p);
00494 
00495     return 0;
00496 }
00497 
00498 
00507 static int fors_pmos_extract_exec(cpl_plugin *plugin)
00508 {
00509     cpl_recipe *recipe;
00510     
00511     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00512         recipe = (cpl_recipe *)plugin;
00513     else 
00514         return -1;
00515 
00516     return fors_pmos_extract(recipe->parameters, recipe->frames);
00517 }
00518 
00519 
00528 static int fors_pmos_extract_destroy(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     cpl_parameterlist_delete(recipe->parameters); 
00538 
00539     return 0;
00540 }
00541 
00542 
00552 static int fors_pmos_extract(cpl_parameterlist *parlist, cpl_frameset *frameset)
00553 {
00554 
00555     const char *recipe = "fors_pmos_extract";
00556 
00557 
00558     /*
00559      * Input parameters
00560      */
00561 
00562     double      dispersion;
00563     int         skyalign;
00564     const char *wcolumn;
00565     double      startwavelength;
00566     double      endwavelength;
00567     int         flux;
00568     int         flatfield;
00569     int         skyglobal;
00570     int         skylocal;
00571     int         skymedian;
00572     int         chromatism;
00573     int         cosmics;
00574     int         slit_margin;
00575     int         ext_radius;
00576     int         cont_radius;
00577     int         ext_mode;
00578     int         time_normalise;
00579     int         check;
00580 
00581     /*
00582      * CPL objects
00583      */
00584 
00585     cpl_image       **images;
00586 
00587     cpl_image       **reduceds       = NULL;
00588     cpl_image       **rerrors        = NULL;
00589     cpl_table       **slitss         = NULL;
00590     cpl_image       **mappeds        = NULL;
00591     cpl_image       **skylocalmaps   = NULL;
00592     
00593     int nobjects = 0;
00594 
00595     cpl_image        *bias           = NULL;
00596     cpl_image        *norm_flat      = NULL;
00597     cpl_image        *spectra        = NULL;
00598     cpl_image        *rectified      = NULL;
00599     cpl_image        *coordinate     = NULL;
00600     cpl_image        *rainbow        = NULL;
00601     cpl_image        *mapped         = NULL;
00602     cpl_image        *mapped_sky     = NULL;
00603     cpl_image        *mapped_cleaned = NULL;
00604     cpl_image        *smapped        = NULL;
00605     cpl_image        *wavemap        = NULL;
00606     cpl_image        *skymap         = NULL;
00607     cpl_image        *skylocalmap    = NULL;
00608     cpl_image        *dummy          = NULL;
00609 
00610     cpl_table        *grism_table    = NULL;
00611     cpl_table        *overscans      = NULL;
00612     cpl_table        *wavelengths    = NULL;
00613     cpl_table        *idscoeff       = NULL;
00614     cpl_table        *slits          = NULL;
00615     cpl_table        *origslits     = NULL;
00616     cpl_table        *maskslits      = NULL;
00617     cpl_table        *polytraces     = NULL;
00618     cpl_table        *offsets        = NULL;
00619     cpl_table        *sky            = NULL;
00620 
00621     cpl_vector       *lines          = NULL;
00622 
00623     cpl_propertylist *header         = NULL;
00624     cpl_propertylist *save_header    = NULL;
00625 
00626     cpl_table        *global         = NULL;
00627     /*
00628      * Auxiliary variables
00629      */
00630 
00631     char    version[80];
00632     char   *instrume = NULL;
00633     const char   *science_tag;
00634     const char   *master_norm_flat_tag;
00635     const char   *disp_coeff_sky_tag;
00636     const char   *wavelength_map_sky_tag;
00637     const char   *reduced_science_tag;
00638     const char   *reduced_sky_tag;
00639     const char   *reduced_error_tag;
00640     const char   *mapped_science_tag;
00641     const char   *unmapped_science_tag;
00642     const char   *mapped_science_sky_tag;
00643     const char   *mapped_sky_tag;
00644     const char   *unmapped_sky_tag;
00645     const char   *global_sky_spectrum_tag;
00646     const char   *object_table_tag;
00647     const char   *object_table_pol_tag;
00648     const char   *skylines_offsets_tag;
00649     const char   *reduced_q_tag;
00650     const char   *reduced_u_tag;
00651     const char   *reduced_v_tag;
00652     const char   *reduced_l_tag;
00653     const char   *reduced_error_q_tag;
00654     const char   *reduced_error_u_tag;
00655     const char   *reduced_error_v_tag;
00656     const char   *reduced_error_l_tag;
00657     const char   *reduced_nul_q_tag;
00658     const char   *reduced_nul_u_tag;
00659     const char   *reduced_nul_v_tag;
00660     const char   *reduced_angle_tag;
00661     const char   *reduced_error_angle_tag;
00662     const char   *master_distortion_tag = "MASTER_DISTORTION_TABLE";
00663     const char   *chrom_table_tag = "RETARDER_WAVEPLATE_CHROMATISM";
00664     float *angles = NULL;
00665     int     pmos, circ;
00666     int     nscience;
00667     double  alltime;
00668     double  mean_rms;
00669     int     nlines;
00670     int     rebin;
00671     double *line;
00672     int     nx = 0, ny;
00673     int     ccd_xsize, ccd_ysize;
00674     double  reference;
00675     double  gain;
00676     double  ron;
00677     int     standard;
00678     int     highres;
00679     int     i, j;
00680     cpl_error_code error;
00681 
00682     int * nobjs_per_slit;
00683 
00684     snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00685 
00686     cpl_msg_set_indentation(2);
00687 
00688     if (dfs_files_dont_exist(frameset))
00689         fors_pmos_extract_exit(NULL);
00690 
00691 
00692     /* 
00693      * Get configuration parameters
00694      */
00695 
00696     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00697     cpl_msg_indent_more();
00698 
00699     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00700         fors_pmos_extract_exit("Too many in input: GRISM_TABLE");
00701 
00702     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00703 
00704     dispersion = dfs_get_parameter_double(parlist, 
00705                     "fors.fors_pmos_extract.dispersion", grism_table);
00706 
00707     if (dispersion <= 0.0)
00708         fors_pmos_extract_exit("Invalid resampling step");
00709 
00710     skyalign = dfs_get_parameter_int(parlist, 
00711                     "fors.fors_pmos_extract.skyalign", NULL);
00712 
00713     if (skyalign > 2)
00714         fors_pmos_extract_exit("Max polynomial degree for sky alignment is 2");
00715 
00716     wcolumn = dfs_get_parameter_string(parlist, 
00717                     "fors.fors_pmos_extract.wcolumn", NULL);
00718 
00719     startwavelength = dfs_get_parameter_double(parlist, 
00720                     "fors.fors_pmos_extract.startwavelength", grism_table);
00721     if (startwavelength < 3000.0 || startwavelength > 13000.0)
00722         fors_pmos_extract_exit("Invalid wavelength");
00723 
00724     endwavelength = dfs_get_parameter_double(parlist, 
00725                     "fors.fors_pmos_extract.endwavelength", grism_table);
00726     if (endwavelength < 3000.0 || endwavelength > 13000.0)
00727         fors_pmos_extract_exit("Invalid wavelength");
00728 
00729     if (endwavelength - startwavelength <= 0.0)
00730         fors_pmos_extract_exit("Invalid wavelength interval");
00731 
00732     flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flux", NULL);
00733 
00734     flatfield = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flatfield", 
00735                                        NULL);
00736 
00737     skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skyglobal", 
00738                                        NULL);
00739     skylocal  = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skylocal", 
00740                                        NULL);
00741     skymedian = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skymedian", 
00742                                        NULL);
00743 /* NSS
00744     skymedian = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.skymedian", 
00745                                        NULL);
00746 */
00747     
00748     chromatism = 
00749     dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.chromatism", 
00750                    NULL);
00751 
00752     if (skylocal && skyglobal)
00753         fors_pmos_extract_exit("Cannot apply both local and global sky subtraction");
00754 
00755     if (skylocal && skymedian)
00756         fors_pmos_extract_exit("Cannot apply sky subtraction both on extracted "
00757                           "and non-extracted spectra");
00758 
00759     cosmics = dfs_get_parameter_bool(parlist, 
00760                                      "fors.fors_pmos_extract.cosmics", NULL);
00761 
00762     if (cosmics)
00763         if (!(skyglobal || skylocal))
00764             fors_pmos_extract_exit("Cosmic rays correction requires "
00765                               "either skylocal=true or skyglobal=true");
00766 
00767     slit_margin = dfs_get_parameter_int(parlist, 
00768                                         "fors.fors_pmos_extract.slit_margin",
00769                                         NULL);
00770     if (slit_margin < 0)
00771         fors_pmos_extract_exit("Value must be zero or positive");
00772 
00773     ext_radius = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_radius",
00774                                        NULL);
00775     if (ext_radius < 0)
00776         fors_pmos_extract_exit("Value must be zero or positive");
00777 
00778     cont_radius = dfs_get_parameter_int(parlist, 
00779                                         "fors.fors_pmos_extract.cont_radius",
00780                                         NULL);
00781     if (cont_radius < 0)
00782         fors_pmos_extract_exit("Value must be zero or positive");
00783 
00784     ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_mode",
00785                                        NULL);
00786     if (ext_mode < 0 || ext_mode > 1)
00787         fors_pmos_extract_exit("Invalid object extraction mode");
00788 
00789     time_normalise = dfs_get_parameter_bool(parlist, 
00790                              "fors.fors_pmos_extract.time_normalise", NULL);
00791 
00792     check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.check", NULL);
00793     cpl_table_delete(grism_table); grism_table = NULL;
00794 
00795     if (cpl_error_get_code())
00796         fors_pmos_extract_exit("Failure getting the configuration parameters");
00797 
00798     
00799     /* 
00800      * Check input set-of-frames
00801      */
00802 
00803     cpl_msg_indent_less();
00804     cpl_msg_info(recipe, "Check input set-of-frames:");
00805     cpl_msg_indent_more();
00806 
00807     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00808         fors_pmos_extract_exit("Input frames are not from the same grism");
00809 
00810     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00811         fors_pmos_extract_exit("Input frames are not from the same filter");
00812 
00813     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00814         fors_pmos_extract_exit("Input frames are not from the same chip");
00815 
00816     standard = 0;
00817     pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS");
00818 
00819     if (pmos == 0) {
00820         pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS");
00821         standard = 1;
00822     }
00823 
00824     if (pmos == 0)
00825         fors_pmos_extract_exit("Missing input scientific frame");
00826 
00827     angles = fors_check_angles(frameset, pmos, 
00828                                 standard ? "STANDARD_PMOS" : "SCIENCE_PMOS", 
00829                                 &circ);
00830     if (angles == NULL)
00831         fors_pmos_extract_exit("Polarization angles could not be read");
00832 
00833     if (circ)
00834         chromatism = 0; /* Chromatism correction unrequired for 
00835                            circular polarimetry */
00836 
00837 
00838     nscience = pmos;
00839 
00840     reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00841     rerrors  = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00842     slitss   = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
00843     mappeds  = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00844     skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00845 
00846     if (pmos) {
00847         cpl_msg_info(recipe, "PMOS data found");
00848         if (standard) {
00849             science_tag             = "STANDARD_PMOS";
00850             reduced_science_tag     = "REDUCED_STD_PMOS";
00851             unmapped_science_tag    = "UNMAPPED_STD_PMOS";
00852             mapped_science_tag      = "MAPPED_STD_PMOS";
00853             mapped_science_sky_tag  = "MAPPED_ALL_STD_PMOS";
00854             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_STD_PMOS";
00855             wavelength_map_sky_tag  = "WAVELENGTH_MAP_STD_PMOS";
00856             disp_coeff_sky_tag      = "DISP_COEFF_STD_PMOS";
00857             mapped_sky_tag          = "MAPPED_SKY_STD_PMOS";
00858             unmapped_sky_tag        = "UNMAPPED_SKY_STD_PMOS";
00859             object_table_tag        = "OBJECT_TABLE_STD_PMOS";
00860             object_table_pol_tag    = "OBJECT_TABLE_POL_STD_PMOS";
00861             reduced_sky_tag         = "REDUCED_SKY_STD_PMOS";
00862             reduced_error_tag       = "REDUCED_ERROR_STD_PMOS";
00863             reduced_q_tag           = "REDUCED_Q_STD_PMOS";
00864             reduced_u_tag           = "REDUCED_U_STD_PMOS";
00865             reduced_v_tag           = "REDUCED_V_STD_PMOS";
00866             reduced_l_tag           = "REDUCED_L_STD_PMOS";
00867             reduced_error_q_tag     = "REDUCED_ERROR_Q_STD_PMOS";
00868             reduced_error_u_tag     = "REDUCED_ERROR_U_STD_PMOS";
00869             reduced_error_v_tag     = "REDUCED_ERROR_V_STD_PMOS";
00870             reduced_error_l_tag     = "REDUCED_ERROR_L_STD_PMOS";
00871             reduced_nul_q_tag       = "REDUCED_NUL_Q_STD_PMOS";
00872             reduced_nul_u_tag       = "REDUCED_NUL_U_STD_PMOS";
00873             reduced_nul_v_tag       = "REDUCED_NUL_V_STD_PMOS";
00874             reduced_angle_tag       = "REDUCED_ANGLE_STD_PMOS";
00875             reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS";
00876         }
00877         else {
00878             science_tag             = "SCIENCE_PMOS";
00879             reduced_science_tag     = "REDUCED_SCI_PMOS";
00880             unmapped_science_tag    = "UNMAPPED_SCI_PMOS";
00881             mapped_science_tag      = "MAPPED_SCI_PMOS";
00882             mapped_science_sky_tag  = "MAPPED_ALL_SCI_PMOS";
00883             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_SCI_PMOS";
00884             wavelength_map_sky_tag  = "WAVELENGTH_MAP_SCI_PMOS";
00885             disp_coeff_sky_tag      = "DISP_COEFF_SCI_PMOS";
00886             mapped_sky_tag          = "MAPPED_SKY_SCI_PMOS";
00887             unmapped_sky_tag        = "UNMAPPED_SKY_SCI_PMOS";
00888             object_table_tag        = "OBJECT_TABLE_SCI_PMOS";
00889             object_table_pol_tag    = "OBJECT_TABLE_POL_SCI_PMOS";
00890             reduced_sky_tag         = "REDUCED_SKY_SCI_PMOS";
00891             reduced_error_tag       = "REDUCED_ERROR_SCI_PMOS";
00892             reduced_q_tag           = "REDUCED_Q_SCI_PMOS";
00893             reduced_u_tag           = "REDUCED_U_SCI_PMOS";
00894             reduced_v_tag           = "REDUCED_V_SCI_PMOS";
00895             reduced_l_tag           = "REDUCED_L_SCI_PMOS";
00896             reduced_error_q_tag     = "REDUCED_ERROR_Q_SCI_PMOS";
00897             reduced_error_u_tag     = "REDUCED_ERROR_U_SCI_PMOS";
00898             reduced_error_v_tag     = "REDUCED_ERROR_V_SCI_PMOS";
00899             reduced_error_l_tag     = "REDUCED_ERROR_L_SCI_PMOS";
00900             reduced_nul_q_tag       = "REDUCED_NUL_Q_SCI_PMOS";
00901             reduced_nul_u_tag       = "REDUCED_NUL_U_SCI_PMOS";
00902             reduced_nul_v_tag       = "REDUCED_NUL_V_SCI_PMOS";
00903             reduced_angle_tag       = "REDUCED_ANGLE_SCI_PMOS";
00904             reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS";
00905         }
00906 
00907         master_norm_flat_tag    = "MASTER_NORM_FLAT_PMOS";
00908         global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_PMOS";
00909 
00910         if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
00911             master_norm_flat_tag    = "MASTER_NORM_FLAT_LONG_PMOS";
00912         }
00913     }
00914 
00915     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
00916         fors_pmos_extract_exit("Missing required input: MASTER_BIAS");
00917 
00918     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00919         fors_pmos_extract_exit("Too many in input: MASTER_BIAS");
00920 
00921     if (skyalign >= 0)
00922         if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
00923             fors_pmos_extract_exit("Too many in input: MASTER_SKYLINECAT");
00924 
00925     if (chromatism) {
00926     if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) {
00927         cpl_msg_error(recipe, "Missing required input: %s",
00928               chrom_table_tag);
00929         fors_pmos_extract_exit(NULL);
00930     }
00931 
00932     if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) {
00933         cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag);
00934         fors_pmos_extract_exit(NULL);
00935     }
00936     }
00937 
00938     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
00939         if (flatfield) {
00940             cpl_msg_error(recipe, "Too many in input: %s", 
00941                           master_norm_flat_tag);
00942             fors_pmos_extract_exit(NULL);
00943         }
00944         else {
00945             cpl_msg_warning(recipe, "%s in input are ignored, "
00946                             "since flat field correction was not requested", 
00947                             master_norm_flat_tag);
00948         }
00949     }
00950 
00951     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
00952         if (!flatfield) {
00953             cpl_msg_warning(recipe, "%s in input is ignored, "
00954                             "since flat field correction was not requested", 
00955                             master_norm_flat_tag);
00956         }
00957     }
00958 
00959     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
00960         if (flatfield) {
00961             cpl_msg_error(recipe, "Flat field correction was requested, "
00962                           "but no %s are found in input",
00963                           master_norm_flat_tag);
00964             fors_pmos_extract_exit(NULL);
00965         }
00966     }
00967 
00968     if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0)
00969         fors_pmos_extract_exit("Missing required input: MASTER_DISTORTION_TABLE");
00970     
00971     if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1)
00972     fors_pmos_extract_exit("Too many in input: MASTER_DISTORTION_TABLE");
00973     
00974     global = dfs_load_table(frameset, master_distortion_tag, 1);
00975     if (global == NULL)
00976     fors_pmos_extract_exit("Cannot load master distortion table");
00977     
00978     cpl_msg_indent_less();
00979 
00980     /*
00981      * Get the reference wavelength and the rebin factor along the
00982      * dispersion direction from a scientific exposure
00983      */
00984 
00985     header = dfs_load_header(frameset, science_tag, 0);
00986 
00987     if (header == NULL)
00988         fors_pmos_extract_exit("Cannot load scientific frame header");
00989 
00990     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00991     if (instrume == NULL)
00992         fors_pmos_extract_exit("Missing keyword INSTRUME in scientific header");
00993     instrume = cpl_strdup(instrume);
00994 
00995     if (instrume[4] == '1')
00996         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00997     if (instrume[4] == '2')
00998         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00999 
01000     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
01001 
01002     if (cpl_error_get_code() != CPL_ERROR_NONE)
01003         fors_pmos_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific "
01004                         "frame header");
01005 
01006     if (reference < 3000.0)   /* Perhaps in nanometers... */
01007         reference *= 10;
01008 
01009     if (reference < 3000.0 || reference > 13000.0) {
01010         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01011                       "keyword ESO INS GRIS1 WLEN in scientific frame header",
01012                       reference);
01013         fors_pmos_extract_exit(NULL);
01014     }
01015 
01016     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01017 
01018     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01019 
01020     if (cpl_error_get_code() != CPL_ERROR_NONE)
01021         fors_pmos_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific "
01022                         "frame header");
01023 
01024     if (rebin != 1) {
01025         dispersion *= rebin;
01026         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01027                         "resampling step used is %f A/pixel", rebin, 
01028                         dispersion);
01029     }
01030 
01031     gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01032 
01033     if (cpl_error_get_code() != CPL_ERROR_NONE)
01034         fors_pmos_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific "
01035                           "frame header");
01036 
01037     cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01038 
01039     ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01040 
01041     if (cpl_error_get_code() != CPL_ERROR_NONE)
01042         fors_pmos_extract_exit("Missing keyword ESO DET OUT1 RON in scientific "
01043                           "frame header");
01044 
01045     ron /= gain;     /* Convert from electrons to ADU */
01046 
01047     cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
01048 
01049     cpl_msg_info(recipe, "Load normalised flat field (if present)...");
01050     cpl_msg_indent_more();
01051 
01052     if (flatfield) {
01053     norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 
01054                    CPL_TYPE_FLOAT, 0, 1);
01055     }
01056 
01057     cpl_msg_info(recipe, "Produce mask slit position table...");
01058 
01059     maskslits = mos_load_slits_fors_pmos(header);
01060 
01061     if (skyalign >= 0) {
01062 
01063     cpl_msg_indent_less();
01064     cpl_msg_info(recipe, "Load input sky line catalog...");
01065     cpl_msg_indent_more();
01066 
01067     wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
01068 
01069     if (wavelengths) {
01070         /*
01071          * Cast the wavelengths into a (double precision) CPL vector
01072          */
01073 
01074         nlines = cpl_table_get_nrow(wavelengths);
01075 
01076         if (nlines == 0)
01077         fors_pmos_extract_exit("Empty input sky line catalog");
01078 
01079         if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01080         cpl_msg_error(recipe, "Missing column %s in input line "
01081                   "catalog table", wcolumn);
01082         fors_pmos_extract_exit(NULL);
01083         }
01084 
01085         line = cpl_malloc(nlines * sizeof(double));
01086     
01087         for (i = 0; i < nlines; i++)
01088         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01089 
01090         cpl_table_delete(wavelengths); wavelengths = NULL;
01091 
01092         lines = cpl_vector_wrap(nlines, line);
01093     }
01094     else {
01095         cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
01096     }
01097     }
01098 
01099 
01100     cpl_propertylist_delete(header); header = NULL;
01101 
01102     /*
01103      * Load the wavelength calibration table
01104      */
01105 
01106     for (j = 0; j < nscience; j++) {
01107     int k;
01108 
01109     cpl_msg_indent_less();
01110     cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f "
01111              "(%d out of %d) ...",
01112              angles[j], j + 1, nscience);
01113     cpl_msg_indent_more();
01114 
01115     cpl_msg_info(recipe, "Load scientific exposure...");
01116     cpl_msg_indent_more();
01117 
01118     /*
01119      * FIXME: Horrible workaround to avoid the problem because of the
01120      * multiple encapsulation of cpl_frameset_find() in different 
01121      * loading functions
01122      */
01123 
01124     header = dfs_load_header(frameset, science_tag, 0);
01125 
01126     for (k = 0; k < j; k ++) {
01127         cpl_propertylist_delete(header);
01128         header = dfs_load_header(frameset, NULL, 0);
01129     }
01130 
01131     spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
01132 
01133     for (k = 0; k < j; k ++) {
01134         cpl_image_delete(spectra);
01135         spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01136     }
01137 
01138     if (spectra == NULL)
01139         fors_pmos_extract_exit("Cannot load scientific frame");
01140         
01141     if (header == NULL)
01142         fors_pmos_extract_exit("Cannot load scientific frame header");
01143 
01144     alltime = cpl_propertylist_get_double(header, "EXPTIME");
01145 
01146     if (cpl_error_get_code() != CPL_ERROR_NONE)
01147         fors_pmos_extract_exit("Missing keyword EXPTIME in scientific "
01148                    "frame header");
01149 
01150     /* Leave the header on for the next step... */
01151     //cpl_propertylist_delete(header); header = NULL;
01152 
01153     cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 
01154              alltime);
01155 
01156     cpl_msg_indent_less();
01157 
01158     /*
01159      * Remove the master bias
01160      */
01161 
01162     cpl_msg_info(recipe, "Remove the master bias...");
01163 
01164     bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
01165 
01166     if (bias == NULL)
01167         fors_pmos_extract_exit("Cannot load master bias");
01168 
01169     overscans = mos_load_overscans_vimos(header, 1);
01170 
01171     dummy = mos_remove_bias(spectra, bias, overscans);
01172     cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
01173     cpl_image_delete(bias); bias = NULL;
01174     cpl_table_delete(overscans); overscans = NULL;
01175 
01176     if (spectra == NULL)
01177         fors_pmos_extract_exit("Cannot remove bias from scientific frame");
01178 
01179     ccd_xsize = nx = cpl_image_get_size_x(spectra);
01180     ccd_ysize = ny = cpl_image_get_size_y(spectra);
01181 
01182     if (flatfield) {
01183 
01184         if (norm_flat) {
01185         cpl_msg_info(recipe, "Apply flat field correction...");
01186         if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
01187             cpl_msg_error(recipe, "Failure of flat field correction: %s",
01188                   cpl_error_get_message());
01189             fors_pmos_extract_exit(NULL);
01190         }
01191         }
01192         else {
01193         cpl_msg_error(recipe, "Cannot load input %s for flat field "
01194                   "correction", master_norm_flat_tag);
01195         fors_pmos_extract_exit(NULL);
01196         }
01197 
01198     }
01199 
01200     /*
01201      * Load the slit location table
01202      */
01203 
01204     slits = mos_build_slit_location(global, maskslits, ny);
01205 
01206     if (slits == NULL) {
01207         fors_pmos_extract_exit("Cannot load slits location table");
01208     } else {
01209         cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT);
01210 
01211         int m, null, size = cpl_table_get_nrow(slits);
01212 
01213         for (m = 0; m < size; m++) {
01214         int slit_id = cpl_table_get(slits, "slit_id", m, &null);
01215 
01216         int pair_id = slit_id % 2 ? slit_id + 1 : slit_id;
01217 
01218         cpl_table_set(slits, "pair_id", m, pair_id);
01219         }
01220     }
01221     
01222     cpl_msg_info(recipe, "Processing scientific spectra...");
01223 
01224     /*
01225      * Load the spectral curvature table
01226      */
01227 
01228     polytraces = mos_build_curv_coeff(global, maskslits, slits);
01229     if (polytraces == NULL)
01230         fors_pmos_extract_exit("Cannot create spectral curvature table");
01231  
01232     /*
01233      * This one will also generate the spatial map from the spectral 
01234      * curvature table (in the case of multislit data)
01235      */
01236 
01237     coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01238 
01239     smapped = mos_spatial_calibration(spectra, slits, polytraces, reference,
01240                       startwavelength, endwavelength,
01241                       dispersion, flux, coordinate);
01242 
01243     /*
01244      * Generate a rectified wavelength map from the wavelength calibration 
01245      * table
01246      */
01247 
01248     /*
01249      * Load the wavelength calibration table
01250      */
01251  
01252     idscoeff = mos_build_disp_coeff(global, slits);
01253     if (idscoeff == NULL)
01254         fors_pmos_extract_exit("Cannot create wavelength calibration table");
01255 
01256     rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 
01257                    endwavelength);
01258 
01259     if (dispersion > 1.0)
01260         highres = 0;
01261     else
01262         highres = 1;
01263 
01264     if (skyalign >= 0) {
01265         if (skyalign) {
01266         cpl_msg_info(recipe, "Align wavelength solution to reference "
01267                  "skylines applying %d order residual fit...", skyalign);
01268         }
01269         else {
01270         cpl_msg_info(recipe, "Align wavelength solution to reference "
01271                  "skylines applying median offset...");
01272         }
01273 
01274         if (!j) {
01275         offsets = mos_wavelength_align(smapped, slits, reference, 
01276                            startwavelength, endwavelength, 
01277                            idscoeff, lines, highres, 
01278                            skyalign, rainbow, 4);
01279 
01280         if (offsets) {
01281             if (standard)
01282             cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01283                     "to reference sky lines may be unreliable in "
01284                     "this case!");
01285 
01286             if (dfs_save_table(frameset, offsets, skylines_offsets_tag,
01287                        NULL, parlist, recipe, version)) {
01288             fors_pmos_extract_exit(NULL);
01289             }
01290 
01291         } else {
01292             cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01293                     "to reference sky lines could not be done!");
01294             skyalign = -1;
01295         }
01296         }
01297 
01298 
01299     }
01300 
01301     wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 
01302                       polytraces, reference, 
01303                       startwavelength, endwavelength,
01304                       dispersion);
01305 
01306 
01307     cpl_image_delete(rainbow); rainbow = NULL;
01308     cpl_image_delete(coordinate); coordinate = NULL;
01309 
01310     /*
01311      * Here the wavelength calibrated slit spectra are created. This frame
01312      * contains sky_science.
01313      */
01314 
01315     mapped_sky = mos_wavelength_calibration(smapped, reference,
01316                         startwavelength, endwavelength,
01317                         dispersion, idscoeff, flux);
01318 
01319     if (!j) {
01320         cpl_msg_indent_less();
01321         cpl_msg_info(recipe, "Check applied wavelength against skylines...");
01322         cpl_msg_indent_more();
01323 
01324         mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength,
01325                        dispersion, 6, highres);
01326 
01327 
01328         cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
01329 
01330         mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01331 
01332         cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
01333              mean_rms, mean_rms * dispersion);
01334     }
01335 
01336     save_header = cpl_propertylist_duplicate(header);
01337 
01338     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01339     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01340     cpl_propertylist_update_double(header, "CRVAL1", 
01341                        startwavelength + dispersion/2);
01342     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01343     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01344        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01345     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01346     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01347     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01348     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01349     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01350     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01351 
01352     if (time_normalise) {
01353         dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
01354         if (!j) {
01355         if(dfs_save_image_null(frameset, parlist,
01356                        mapped_science_sky_tag,
01357                        recipe, version)) {
01358             fors_pmos_extract_exit(NULL);
01359         }
01360         }
01361         if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) {
01362         fors_pmos_extract_exit(NULL);
01363         }
01364         cpl_image_delete(dummy); dummy = NULL;
01365     }
01366     else {
01367 
01368         if (!j) {
01369         if(dfs_save_image_null(frameset, parlist,
01370                        mapped_science_sky_tag,
01371                        recipe, version)) {
01372             fors_pmos_extract_exit(NULL);
01373         }
01374         }
01375 
01376         if (dfs_save_image_ext(mapped_sky,
01377                    mapped_science_sky_tag, header)) {
01378         fors_pmos_extract_exit(NULL);
01379         }
01380 
01381     }
01382 
01383 /*    if (skyglobal == 0 && skymedian < 0) {    NSS */
01384     if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
01385         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01386     }
01387 
01388     if (skyglobal || skylocal) {
01389 
01390         cpl_msg_indent_less();
01391 
01392         if (skyglobal) {
01393         cpl_msg_info(recipe, "Global sky determination...");
01394         cpl_msg_indent_more();
01395         skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01396 
01397         sky = mos_sky_map_super(spectra, wavemap, dispersion, 
01398                     2.0, 50, skymap);
01399 
01400         if (sky) {
01401             cpl_image_subtract(spectra, skymap);
01402         }
01403         else {
01404             cpl_image_delete(skymap); skymap = NULL;
01405         }
01406         }
01407         else {
01408         cpl_msg_info(recipe, "Local sky determination...");
01409         cpl_msg_indent_more();
01410         skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
01411                       startwavelength, endwavelength, dispersion);
01412         }
01413 
01414         if (skymap) {
01415         if (skyglobal) {
01416             if (time_normalise)
01417             cpl_table_divide_scalar(sky, "sky", alltime);
01418 
01419 /* Old saving:
01420 
01421             if (!j) {
01422             if (dfs_save_table(frameset, sky,
01423                        global_sky_spectrum_tag, 
01424                        NULL, parlist, recipe, version)) {
01425                 fors_pmos_extract_exit(NULL);
01426             }
01427             } else {
01428             if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 
01429                            NULL)) {
01430                 fors_pmos_extract_exit(NULL);
01431             }
01432             }
01433 
01434 End of old saving */
01435 
01436                     if (!j) {
01437                         if(dfs_save_image_null(frameset, parlist, 
01438                                                global_sky_spectrum_tag,
01439                                                recipe, version)) {
01440                 fors_pmos_extract_exit(NULL);
01441                         }
01442                     }
01443     
01444                     if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 
01445                                            NULL)) {
01446                         fors_pmos_extract_exit(NULL);
01447                     }
01448     
01449     
01450             cpl_table_delete(sky); sky = NULL;
01451         }
01452 
01453 //      save_header = dfs_load_header(frameset, science_tag, 0);
01454 
01455         if (time_normalise)
01456             cpl_image_divide_scalar(skymap, alltime);
01457 
01458         if (!j) {
01459             if(dfs_save_image_null(frameset, parlist,
01460                        unmapped_sky_tag,
01461                        recipe, version)) {
01462             fors_pmos_extract_exit(NULL);
01463             }
01464         }
01465 
01466         if (dfs_save_image_ext(skymap, unmapped_sky_tag,
01467                        save_header)) {
01468             fors_pmos_extract_exit(NULL);
01469         }
01470 
01471         cpl_image_delete(skymap); skymap = NULL;
01472 
01473         if (!j) {
01474             if(dfs_save_image_null(frameset, parlist,
01475                        unmapped_science_tag,
01476                        recipe, version)) {
01477             fors_pmos_extract_exit(NULL);
01478             }
01479         }
01480 
01481         if (dfs_save_image_ext(spectra, unmapped_science_tag,
01482                        save_header)) {
01483             fors_pmos_extract_exit(NULL);
01484         }
01485 
01486 //      cpl_propertylist_delete(save_header); save_header = NULL;
01487 
01488         if (cosmics) {
01489             cpl_msg_info(recipe, "Removing cosmic rays...");
01490             mos_clean_cosmics(spectra, gain, -1., -1.);
01491         }
01492 
01493         /*
01494          * The spatially rectified image, that contained the sky,
01495          * is replaced by a sky-subtracted spatially rectified image:
01496          */
01497 
01498         cpl_image_delete(smapped); smapped = NULL;
01499 
01500         smapped = mos_spatial_calibration(spectra, slits, polytraces, 
01501                           reference, startwavelength, 
01502                           endwavelength, dispersion, 
01503                           flux, NULL);
01504         }
01505         else {
01506         cpl_msg_warning(recipe, "Sky subtraction failure");
01507         if (cosmics)
01508             cpl_msg_warning(recipe, "Cosmic rays removal not performed!");
01509         cosmics = skylocal = skyglobal = 0;
01510         }
01511     }
01512 
01513     cpl_image_delete(spectra); spectra = NULL;
01514     cpl_table_delete(polytraces); polytraces = NULL;
01515 
01516     if (skyalign >= 0) {
01517         save_header = dfs_load_header(frameset, science_tag, 0);
01518 
01519         if (!j) {
01520         if(dfs_save_image_null(frameset, parlist,
01521                        wavelength_map_sky_tag,
01522                        recipe, version)) {
01523             fors_pmos_extract_exit(NULL);
01524         }
01525         }
01526 
01527         if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag,
01528                    save_header)) {
01529         fors_pmos_extract_exit(NULL);
01530         }
01531 
01532 //      cpl_propertylist_delete(save_header); save_header = NULL;
01533     }
01534 
01535     cpl_image_delete(wavemap); wavemap = NULL;
01536 
01537     mapped = mos_wavelength_calibration(smapped, reference,
01538                         startwavelength, endwavelength,
01539                         dispersion, idscoeff, flux);
01540 
01541     cpl_image_delete(smapped); smapped = NULL;
01542 
01543     if (skyalign >= 0) {
01544         if (!j) {
01545         if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag,
01546                    NULL, parlist, recipe, version)) {
01547             fors_pmos_extract_exit(NULL);
01548         }
01549         }
01550     }
01551 
01552 /*    if (skymedian >= 0) {    NSS */
01553     if (skymedian) {
01554             cpl_msg_indent_less();
01555             cpl_msg_info(recipe, "Local sky determination...");
01556             cpl_msg_indent_more();
01557        
01558 /*   NSS      skylocalmap = mos_sky_local(mapped, slits, skymedian); */
01559 /*            skylocalmap = mos_sky_local(mapped, slits, 0);        */
01560             skylocalmap = mos_sky_local_old(mapped, slits);       
01561             cpl_image_subtract(mapped, skylocalmap);
01562 /*
01563   if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 
01564   parlist, recipe, version))
01565   fors_pmos_extract_exit(NULL);
01566 */
01567             cpl_image_delete(skylocalmap); skylocalmap = NULL;
01568     }
01569 
01570 /*    if (skyglobal || skymedian >= 0 || skylocal) {   NSS */
01571     if (skyglobal || skymedian || skylocal) {
01572 
01573         skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
01574 
01575         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01576 
01577         if (time_normalise) {
01578         dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
01579 
01580         if (!j) {
01581             if(dfs_save_image_null(frameset, parlist,
01582                        mapped_sky_tag,
01583                        recipe, version)) {
01584             fors_pmos_extract_exit(NULL);
01585             }
01586         }
01587 
01588         if (dfs_save_image_ext(dummy, mapped_sky_tag,
01589                        header)) {
01590             fors_pmos_extract_exit(NULL);
01591         }
01592 
01593         cpl_image_delete(dummy); dummy = NULL;
01594         }
01595         else {
01596         if (!j) {
01597             if(dfs_save_image_null(frameset, parlist,
01598                        mapped_sky_tag,
01599                        recipe, version)) {
01600             fors_pmos_extract_exit(NULL);
01601             }
01602         }
01603 
01604         if (dfs_save_image_ext(skylocalmap, mapped_sky_tag,
01605                        header)) {
01606             fors_pmos_extract_exit(NULL);
01607         }
01608         }
01609 
01610         skylocalmaps[j] = skylocalmap;
01611 
01612         cpl_msg_indent_less();
01613         cpl_msg_info(recipe, "Object detection...");
01614         cpl_msg_indent_more();
01615 
01616         if (!j)
01617         origslits = cpl_table_duplicate(slits);
01618 
01619         if (cosmics || nscience > 1) {
01620         dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius, 
01621                        cont_radius);
01622         }
01623         else {
01624         mapped_cleaned = cpl_image_duplicate(mapped);
01625         mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
01626         dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 
01627                        ext_radius, cont_radius);
01628 
01629         cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
01630         }
01631 
01632         cpl_image_delete(dummy); dummy = NULL;
01633 
01634         if (check) {
01635 
01636 /* Old saving:
01637 
01638         if (!j) {
01639             if (dfs_save_table(frameset, slits, object_table_tag,
01640                        NULL, parlist, recipe, version)) {
01641             fors_pmos_extract_exit(NULL);
01642             }
01643         } else {
01644             if (dfs_save_table_ext(slits, object_table_tag, NULL)) {
01645             fors_pmos_extract_exit(NULL);
01646             }
01647         }
01648 
01649 End old saving */
01650 
01651                 if (!j) {
01652                     if(dfs_save_image_null(frameset, parlist,
01653                                            object_table_tag,
01654                                            recipe, version)) {
01655                         fors_pmos_extract_exit(NULL);
01656                     }
01657                 }
01658 
01659                 if (dfs_save_table_ext(slits, object_table_tag, NULL)) {
01660                     fors_pmos_extract_exit(NULL);
01661                 }
01662         }
01663     }
01664 
01665     slitss[j]  = slits;
01666     mappeds[j] = mapped;
01667 
01668     cpl_msg_indent_less();
01669 
01670     cpl_propertylist_delete(header); header = NULL;
01671     cpl_propertylist_delete(save_header); save_header = NULL;
01672 
01673     cpl_table_delete(idscoeff); idscoeff = NULL;
01674     }
01675 
01676     cpl_table_delete(offsets); offsets = NULL;
01677 
01678     cpl_image_delete(norm_flat); norm_flat = NULL;
01679     cpl_vector_delete(lines); lines = NULL;
01680 
01681     cpl_table_delete(maskslits); maskslits = NULL;
01682 
01683     
01684     cpl_msg_indent_less();
01685     cpl_msg_info(recipe, 
01686          "Check object detection in both beams for all angles...");
01687     cpl_msg_indent_more();
01688 
01689     /* House keeping - selection of objects for which information required 
01690        for Stokes parameters computation is present */
01691     error = mos_object_intersect(slitss, origslits, nscience, 5.0);
01692     if (error == CPL_ERROR_DATA_NOT_FOUND) {
01693         cpl_msg_warning(recipe, "No objects found: no Stokes "
01694                        "parameters to compute!");
01695         for (j = 0; j < nscience; j++)
01696             cpl_table_delete(slitss[j]);
01697         cpl_free(slitss);
01698         cpl_table_delete(origslits);
01699         return 0;
01700     } else if (error) {
01701         fors_pmos_extract_exit("Problem in polarimetric object selection");
01702     }
01703 
01704     if (dfs_save_table(frameset, origslits, object_table_pol_tag,
01705                NULL, parlist, recipe, version)) {
01706     fors_pmos_extract_exit(NULL);
01707     }
01708 
01709     nobjs_per_slit = fors_get_nobjs_perslit(origslits);
01710 
01711     cpl_msg_indent_less();
01712     cpl_msg_info(recipe, "Object extraction...");
01713     cpl_msg_indent_more();
01714 
01715     for (j = 0; j < nscience; j++) {
01716     int k;
01717 
01718     header = dfs_load_header(frameset, science_tag, 0);
01719 
01720     for (k = 0; k < j; k ++) {
01721         cpl_propertylist_delete(header);
01722         header = dfs_load_header(frameset, NULL, 0);
01723     }
01724 
01725     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01726     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01727     cpl_propertylist_update_double(header, "CRVAL1", 
01728                        startwavelength + dispersion/2);
01729     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01730     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01731        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01732     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01733     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01734     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01735     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01736     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01737     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01738 
01739     if (skyglobal || skymedian || skylocal) {
01740 
01741         cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...",
01742              angles[j], j + 1, nscience);
01743 
01744         images = mos_extract_objects(mappeds[j], skylocalmaps[j],
01745                      origslits, 
01746                      ext_mode, ron, gain, 1);
01747 
01748         cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
01749 
01750         if (images) {
01751         if (time_normalise)
01752             cpl_image_divide_scalar(images[0], alltime);
01753 
01754         if (!j) {
01755             if(dfs_save_image_null(frameset, parlist,
01756                        reduced_science_tag,
01757                        recipe, version)) {
01758             fors_pmos_extract_exit(NULL);
01759             }
01760         }
01761 
01762         if (dfs_save_image_ext(images[0], reduced_science_tag,
01763                        header)) {
01764             fors_pmos_extract_exit(NULL);
01765         }
01766 
01767         reduceds[j] = images[0];
01768 //      cpl_image_delete(images[0]);
01769     
01770         if (time_normalise)
01771             cpl_image_divide_scalar(images[1], alltime);
01772 
01773         if (!j) {
01774             if(dfs_save_image_null(frameset, parlist,
01775                        reduced_sky_tag,
01776                        recipe, version)) {
01777             fors_pmos_extract_exit(NULL);
01778             }
01779         }
01780 
01781         if (dfs_save_image_ext(images[1], reduced_sky_tag,
01782                        header)) {
01783             fors_pmos_extract_exit(NULL);
01784         }
01785         cpl_image_delete(images[1]);
01786     
01787         if (time_normalise)
01788             cpl_image_divide_scalar(images[2], alltime);
01789 
01790         if (!j) {
01791             if(dfs_save_image_null(frameset, parlist,
01792                        reduced_error_tag,
01793                        recipe, version)) {
01794             fors_pmos_extract_exit(NULL);
01795             }
01796         }
01797 
01798         if (dfs_save_image_ext(images[2], reduced_error_tag,
01799                        header)) {
01800             fors_pmos_extract_exit(NULL);
01801         }
01802 
01803         rerrors[j] = images[2];
01804 //      cpl_image_delete(images[2]);
01805 
01806         cpl_free(images);
01807         }
01808         else {
01809         cpl_msg_warning(recipe, "No objects found: the products "
01810                 "%s, %s, and %s are not created", 
01811                 reduced_science_tag, reduced_sky_tag, 
01812                 reduced_error_tag);
01813         }
01814 
01815     }
01816 
01817 //  slitss[j] = slits;
01818 //  cpl_table_delete(slits); slits = NULL;
01819 
01820 
01821 /*    if (skyglobal || skymedian >= 0) {   NSS */
01822     if (skyglobal || skymedian || skylocal) {
01823         if (time_normalise)
01824         cpl_image_divide_scalar(mappeds[j], alltime);
01825 
01826         if (!j) {
01827         if(dfs_save_image_null(frameset, parlist,
01828                        mapped_science_tag,
01829                        recipe, version)) {
01830             fors_pmos_extract_exit(NULL);
01831         }
01832         }
01833 
01834         if (dfs_save_image_ext(mappeds[j], mapped_science_tag,
01835                    header)) {
01836         fors_pmos_extract_exit(NULL);
01837         }
01838     }
01839 
01840     cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
01841     cpl_propertylist_delete(header); header = NULL;
01842 
01843     }
01844 
01845     cpl_table_delete(origslits);
01846 
01847     /* Stokes computation */
01848 
01849     nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
01850     nx       = cpl_image_get_size_x(reduceds[0]);
01851 
01852     header = cpl_propertylist_new();
01853     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01854     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01855     cpl_propertylist_update_double(header, "CRVAL1", 
01856                    startwavelength + dispersion/2);
01857     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01858     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01859        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01860     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01861     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01862     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01863     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01864     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01865     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01866     
01867     if (circ) {
01868 
01869     cpl_image        *pv_im          = NULL;
01870     cpl_image        *pvnull_im      = NULL;
01871     cpl_image        *perr_im        = NULL;
01872 
01873     double           *p_v            = NULL;
01874     double           *p_vnull        = NULL;
01875     double           *perr           = NULL;
01876 
01877     double            mean_vnull;
01878 
01879     int p = -1;
01880     int total = 0;
01881 
01882     pv_im     = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01883     perr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01884 
01885     p_v     = cpl_image_get_data_double(pv_im);
01886     perr    = cpl_image_get_data_double(perr_im);
01887 
01888     if (nscience / 2 > 1) {
01889         pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01890         p_vnull = cpl_image_get_data_double(pvnull_im);
01891     }
01892 
01893     for (j = 0; j < nobjects; j++) {
01894         int k, m;
01895 
01896         double * ip_v,
01897            * ip_vnull, * iperr;
01898 
01899         float * data;
01900         float * iff,  * ierr;
01901 
01902         ip_v = p_v + (nobjects - 1 - j) * nx;
01903 
01904         if (nscience / 2 > 1)
01905         ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
01906 
01907         iperr = perr + (nobjects - 1 - j) * nx;
01908 
01909         while (total < j + 1) {
01910         p++;
01911         total += nobjs_per_slit[p];
01912         }
01913 
01914         for (k = 0; k < nscience / 2; k++) {
01915         float * if_o,  * if_e,  * ifdelta_o, * ifdelta_e;
01916 
01917         int pos   = fors_find_angle_pos(angles, nscience, 180 * k - 45);
01918         int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
01919 
01920         data = cpl_image_get_data_float(reduceds[pos]);
01921 
01922         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
01923                    + (total - j - 1)) * nx;
01924 
01925         if_e = data + (2 * (nobjects - total) 
01926                    + (total - j - 1)) * nx;
01927 
01928 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
01929 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
01930 
01931         data = cpl_image_get_data_float(reduceds[pos_d]);
01932 
01933         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
01934                    + (total - j - 1)) * nx;
01935 
01936         ifdelta_e = data + (2 * (nobjects - total) 
01937                    + (total - j - 1)) * nx;
01938 
01939 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
01940 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
01941 
01942         for (m = 0; m < nx; m++) {
01943 
01944             double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
01945             (if_o[m]      - if_e[m]     ) /
01946             (if_o[m]      + if_e[m]     ) -
01947             (ifdelta_o[m] - ifdelta_e[m]) /
01948             (ifdelta_o[m] + ifdelta_e[m]);
01949 
01950             quantity = isfinite(quantity) ? quantity : 0.0;
01951 
01952             /* PQ map computation */
01953             ip_v[m] += quantity * 0.5 / (nscience / 2);
01954 
01955             /* PQnull map computation */
01956             if (nscience / 2 > 1) {
01957             if (k % 2)
01958                 ip_vnull[m] += quantity * 0.5 / (nscience / 2);
01959             else
01960                 ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
01961             }
01962         }
01963         }
01964 
01965         /* Error map */
01966         data = cpl_image_get_data_float(reduceds[0]);
01967         iff  = data +  2 * (nobjects - 1 - j)      * nx;
01968 
01969         data = cpl_image_get_data_float(rerrors[0]);
01970         ierr = data +  2 * (nobjects - 1 - j)      * nx;
01971 
01972         for (m = 0; m < nx; m++)
01973         iperr[m] = iff[m] <= 0.0 ? 
01974             0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
01975 
01976         if (nscience / 2 > 1) {
01977         float * weights;
01978         float   max, sum, sum2, imean;
01979 
01980         int k;
01981 
01982         /* QC on U NULL */
01983         weights = cpl_malloc(sizeof(float) * nx);
01984 
01985         max = 0.0;
01986         for (k = 0; k < nx; k++) {
01987             if (max < iff[k]) max = iff[k];
01988         }
01989         
01990         for (k = 0; k < nx; k++) {
01991             weights[k] = iff[k] < 0.0 ? 
01992             0.0 : iff[k] * iff[k] / (max * max);
01993         }
01994         
01995         sum  = 0.0;
01996         sum2 = 0.0;
01997         for (k = 0; k < nx; k++) {
01998             sum  += weights[k] * ip_vnull[k];
01999             sum2 += weights[k];
02000         }
02001 
02002         cpl_free(weights);
02003 
02004         imean = sum / sum2;
02005 
02006         mean_vnull += (imean - mean_vnull) / (j + 1.0);
02007         }
02008     }
02009 
02010     if (dfs_save_image(frameset, pv_im, reduced_v_tag, header, 
02011                parlist, recipe, version))
02012         fors_pmos_extract_exit(NULL);
02013 
02014     if (nscience / 2 > 1) {
02015         char * pipefile, * keyname;
02016         cpl_propertylist * qheader = dfs_load_header(frameset, science_tag, 0);
02017 
02018             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02019             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02020             cpl_propertylist_update_double(qheader, "CRVAL1", 
02021                                startwavelength + dispersion/2);
02022             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02023             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02024                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02025             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02026             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02027             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02028             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02029             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02030             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02031 
02032         fors_qc_start_group(qheader, "2.0", instrume);
02033 
02034         /*
02035          * QC1 group header
02036          */
02037 
02038         if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag,
02039                      "Product category", instrume))
02040         fors_pmos_extract_exit("Cannot write product category to "
02041                      "QC log file");
02042 
02043         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02044                        "DPR type", instrume))
02045         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02046                      "lamp header");
02047 
02048         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02049                        "Template", instrume))
02050         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02051                      "lamp header");
02052 
02053         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02054                        "Grism name", instrume))
02055         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02056                      "lamp header");
02057 
02058         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02059                        "Grism identifier", instrume))
02060         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02061                      "lamp header");
02062 
02063         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02064         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02065                        "Filter name", instrume);
02066 
02067         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02068                        "Collimator name", instrume))
02069         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02070                      "lamp header");
02071 
02072         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02073                        "Chip identifier", instrume))
02074         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02075                      "lamp header");
02076 
02077         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02078                        "Archive name of input data", 
02079                        instrume))
02080         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02081                      "lamp header");
02082 
02083         pipefile = dfs_generate_filename_tfits(reduced_nul_v_tag);
02084         if (fors_qc_write_string("PIPEFILE", pipefile,
02085                      "Pipeline product name", instrume))
02086         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02087         cpl_free(pipefile); pipefile = NULL;
02088 
02089 
02090         /*
02091          * QC1 parameters
02092          */
02093 
02094         keyname = "QC.NULL.V.MEAN";
02095             
02096         if (fors_qc_write_qc_double(qheader, mean_vnull,
02097                     keyname, NULL,
02098                     "Mean V null parameter",
02099                     instrume)) {
02100         fors_pmos_extract_exit("Cannot write mean Q null parameter "
02101                      "to QC log file");
02102         }
02103 
02104         fors_qc_end_group();
02105 
02106         if (dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader, 
02107                    parlist, recipe, version))
02108         fors_pmos_extract_exit(NULL);
02109 
02110         cpl_propertylist_delete(qheader);
02111     }
02112 
02113     if (dfs_save_image(frameset, perr_im, reduced_error_v_tag, header, 
02114                parlist, recipe, version))
02115         fors_pmos_extract_exit(NULL);
02116 
02117     cpl_image_delete(pv_im);
02118     cpl_image_delete(pvnull_im);
02119     cpl_image_delete(perr_im);
02120     } else {
02121     cpl_image        *pq_im          = NULL;
02122     cpl_image        *pu_im          = NULL;
02123     cpl_image        *pl_im          = NULL;
02124 
02125     cpl_image        *pqnull_im      = NULL;
02126     cpl_image        *punull_im      = NULL;
02127 
02128     cpl_image        *pqerr_im        = NULL;
02129     cpl_image        *puerr_im        = NULL;
02130     cpl_image        *plerr_im        = NULL;
02131 
02132     cpl_image        *pang_im        = NULL;
02133     cpl_image        *pangerr_im        = NULL;
02134 
02135     double           *p_q            = NULL;
02136     double           *p_u            = NULL;
02137     double           *p_l            = NULL;
02138 
02139     double           *p_qnull        = NULL;
02140     double           *p_unull        = NULL;
02141 
02142     double           *pqerr           = NULL;
02143     double           *puerr           = NULL;
02144     double           *plerr           = NULL;
02145 
02146     double           *pang           = NULL;
02147     double           *pangerr           = NULL;
02148 
02149     int k, m;
02150 
02151     cpl_image * correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
02152     double    * correct    = cpl_image_get_data_double(correct_im);
02153 
02154     double mean_unull, mean_qnull;
02155 
02156     int p = -1;
02157     int total = 0;
02158 
02159     pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02160     pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02161     pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02162 
02163     pqerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02164     puerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02165     plerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02166 
02167     pang_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02168     pangerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02169 
02170     p_q = cpl_image_get_data_double(pq_im);
02171     p_u = cpl_image_get_data_double(pu_im);
02172     p_l = cpl_image_get_data_double(pl_im);
02173 
02174     if (nscience / 4 > 1) {
02175         pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02176         punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02177 
02178         p_qnull = cpl_image_get_data_double(pqnull_im);
02179         p_unull = cpl_image_get_data_double(punull_im);
02180     } else {
02181         cpl_msg_warning(cpl_func, 
02182                 "Not enough pairs to compute null parameters");
02183     }
02184 
02185     pqerr = cpl_image_get_data_double(pqerr_im);
02186     puerr = cpl_image_get_data_double(puerr_im);
02187     plerr = cpl_image_get_data_double(plerr_im);
02188 
02189     pang = cpl_image_get_data_double(pang_im);
02190     pangerr = cpl_image_get_data_double(pangerr_im);
02191 
02192     if (chromatism) {
02193         cpl_table * chrotbl = 
02194         dfs_load_table(frameset, chrom_table_tag, 1);
02195 
02196         int      nrow   = cpl_table_get_nrow(chrotbl);
02197         float  * lambda = cpl_table_get_data_float(chrotbl, "lambda");
02198         float  * theta  = cpl_table_get_data_float(chrotbl, "eps_theta");
02199 
02200         for (j = 0; j < nx; j++) {
02201         double c_wave = 
02202             startwavelength + dispersion / 2 + j * dispersion;
02203         
02204         int found = 0;
02205 
02206         for (k = 0; k < nrow - 1; k++) {
02207             if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
02208             found = 1;
02209             break;
02210             }
02211         }
02212 
02213         if (found) {
02214             correct[j] = (theta [k + 1] - theta [k]) /
02215                      (lambda[k + 1] - lambda[k]) *
02216                      (c_wave        - lambda[k])   + theta[k];
02217                     correct[j] *= M_PI / 180;   /* Radians */
02218         }
02219                 else if (j)
02220                     correct[j] = correct[j-1];
02221                 else
02222                     correct[j] = 0.0;
02223 
02224         }
02225 
02226         cpl_table_delete(chrotbl);
02227     }
02228 
02229     for (j = 0; j < nobjects; j++) {
02230         double * ip_q,     * ip_u, * ip_l, 
02231         * ip_qnull, * ip_unull, * ipqerr, * ipuerr, * iplerr,
02232         * ipang, * ipangerr;
02233 
02234         float * data;
02235         float * iffq,  * ierrq, * iffu, * ierru;
02236 
02237         int pos, pos_d;
02238 
02239         ip_q = p_q + (nobjects - 1 - j) * nx;
02240         ip_u = p_u + (nobjects - 1 - j) * nx;
02241         ip_l = p_l + (nobjects - 1 - j) * nx;
02242 
02243         if (nscience / 4 > 1) {
02244         ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
02245         ip_unull = p_unull + (nobjects - 1 - j) * nx;
02246         }
02247 
02248         ipqerr = pqerr + (nobjects - 1 - j) * nx;
02249         ipuerr = puerr + (nobjects - 1 - j) * nx;
02250         iplerr = plerr + (nobjects - 1 - j) * nx;
02251 
02252         ipang = pang + (nobjects - 1 - j) * nx;
02253         ipangerr = pangerr + (nobjects - 1 - j) * nx;
02254 
02255         while (total < j + 1) {
02256         p++;
02257         total += nobjs_per_slit[p];
02258         }
02259 
02260         for (k = 0; k < nscience / 4; k++) {
02261         float * if_o,  * if_e,  * ifdelta_o, * ifdelta_e;
02262 
02263         /* First P_Q */
02264 
02265         pos   = fors_find_angle_pos(angles, nscience, 90 * k);
02266         pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
02267 
02268         data = cpl_image_get_data_float(reduceds[pos]);
02269 
02270         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02271                    + (total - j - 1)) * nx;
02272 
02273         if_e = data + (2 * (nobjects - total) 
02274                    + (total - j - 1)) * nx;
02275 
02276 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02277 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
02278 
02279         data = cpl_image_get_data_float(reduceds[pos_d]);
02280 
02281         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02282                    + (total - j - 1)) * nx;
02283 
02284         ifdelta_e = data + (2 * (nobjects - total) 
02285                    + (total - j - 1)) * nx;
02286 
02287 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02288 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
02289 
02290         for (m = 0; m < nx; m++) {
02291 
02292             double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02293             (if_o[m]      - if_e[m]     ) /
02294             (if_o[m]      + if_e[m]     ) -
02295             (ifdelta_o[m] - ifdelta_e[m]) /
02296             (ifdelta_o[m] + ifdelta_e[m]);
02297 
02298             quantity = isfinite(quantity) ? quantity : 0.0;
02299 
02300             /* PQ map computation */
02301             ip_q[m] += quantity * 0.5 / (nscience / 4);
02302 
02303             /* PQnull map computation */
02304             if (nscience / 4 > 1) {
02305             if (k % 2)
02306                 ip_qnull[m] += quantity * 0.5 / (nscience / 4);
02307             else
02308                 ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
02309             }
02310         }
02311 
02312         /* Now P_U */
02313 
02314         pos   = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
02315         pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
02316 
02317         data = cpl_image_get_data_float(reduceds[pos]);
02318 
02319         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02320                    + (total - j - 1)) * nx;
02321 
02322         if_e = data + (2 * (nobjects - total) 
02323                    + (total - j - 1)) * nx;
02324 
02325 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02326 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
02327 
02328         data = cpl_image_get_data_float(reduceds[pos_d]);
02329 
02330         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02331                    + (total - j - 1)) * nx;
02332 
02333         ifdelta_e = data + (2 * (nobjects - total) 
02334                    + (total - j - 1)) * nx;
02335 
02336 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02337 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
02338 
02339         for (m = 0; m < nx; m++) {
02340 
02341             double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02342             (if_o[m]      - if_e[m]     ) /
02343             (if_o[m]      + if_e[m]     ) -
02344             (ifdelta_o[m] - ifdelta_e[m]) /
02345             (ifdelta_o[m] + ifdelta_e[m]);
02346 
02347             quantity = isfinite(quantity) ? quantity : 0.0;
02348 
02349             /* PU map computation */
02350             ip_u[m] += quantity * 0.5 / (nscience / 4);
02351 
02352             /* PUnull map computation */
02353             if (nscience / 4 > 1) {
02354             if (k % 2)
02355                 ip_unull[m] += quantity * 0.5 / (nscience / 4);
02356             else
02357                 ip_unull[m] -= quantity * 0.5 / (nscience / 4);
02358             }
02359         }
02360         }
02361 
02362         /* Error map */
02363 
02364         pos   = fors_find_angle_pos(angles, nscience, 0.0);
02365 
02366         data = cpl_image_get_data_float(reduceds[pos]);
02367         iffq  = data +  2 * (nobjects - 1 - j)      * nx;
02368 
02369         data = cpl_image_get_data_float(rerrors[pos]);
02370         ierrq = data +  2 * (nobjects - 1 - j)      * nx;
02371         
02372         pos   = fors_find_angle_pos(angles, nscience, 22.5);
02373 
02374         data = cpl_image_get_data_float(reduceds[pos]);
02375         iffu  = data +  2 * (nobjects - 1 - j)      * nx;
02376 
02377         data = cpl_image_get_data_float(rerrors[pos]);
02378         ierru = data +  2 * (nobjects - 1 - j)      * nx;
02379 
02380         for (m = 0; m < nx; m++) {
02381 
02382         double radicand; 
02383 
02384         ipqerr[m] = iffq[m] <= 0.0 ? 
02385             0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
02386 
02387         ipuerr[m] = iffu[m] <= 0.0 ? 
02388             0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
02389 
02390         iplerr[m] = CPL_MATH_SQRT1_2 * 0.5 * (ipqerr[m] + ipuerr[m]);
02391 
02392 /* Added: */
02393         if (chromatism) {
02394             ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 
02395                               ip_u[m] * sin(2 * correct[m]);
02396 
02397             ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 
02398                               ip_u[m] * cos(2 * correct[m]);
02399         }
02400 /* End added */
02401 
02402         /* PL computation */
02403         ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
02404 
02405         /* P angle computation */
02406         ipang[m] = (ip_q[m] == 0.0 ?
02407             (ip_u[m] > 0.0 ? 45.0 : 135.0)
02408             : 0.5 * (atan2(ip_u[m], ip_q[m]) * 180 / M_PI + 
02409                  ((atan2(ip_u[m], ip_q[m]) > 0.0 ? 0.0 : 360.0))));
02410 
02411         /* Error on the angle computation */
02412         radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] + 
02413                    ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
02414   
02415         ipangerr[m] = ip_l[m] == 0.0 ? 0.0 :
02416              sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI;
02417 
02418                 /* 
02419                  * Note: no need to apply chromatism correction to angle,
02420                  * it is implicit in Q and U correction applied before.
02421                  */
02422 
02423 /* Removed: 
02424         if (chromatism) {
02425             ipang[m] -= correct[m];
02426         
02427             ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 
02428                               ip_u[m] * sin(2 * correct[m]);
02429 
02430             ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 
02431                               ip_u[m] * cos(2 * correct[m]);
02432         
02433         }
02434   end removed */
02435         }
02436 
02437         if (nscience / 4 > 1) {
02438         float * weights;
02439         float   max, sum, sum2, imean;
02440 
02441         int k;
02442 
02443         /* QC on U NULL */
02444         weights = cpl_malloc(sizeof(float) * nx);
02445 
02446         max = 0.0;
02447         for (k = 0; k < nx; k++) {
02448             if (max < iffq[k]) max = iffq[k];
02449         }
02450         
02451         for (k = 0; k < nx; k++) {
02452             weights[k] = iffq[k] < 0.0 ? 
02453             0.0 : iffq[k] * iffq[k] / (max * max);
02454         }
02455         
02456         sum  = 0.0;
02457         sum2 = 0.0;
02458         for (k = 0; k < nx; k++) {
02459             sum  += weights[k] * ip_qnull[k];
02460             sum2 += weights[k];
02461         }
02462 
02463         cpl_free(weights);
02464 
02465         imean = sum / sum2;
02466 
02467         mean_qnull += (imean - mean_qnull) / (j + 1.0);
02468           
02469         /* QC on U NULL */
02470         weights = cpl_malloc(sizeof(float) * nx);
02471         
02472         max = 0.0;
02473         for (k = 0; k < nx; k++) {
02474             if (max < iffu[k]) max = iffu[k];
02475         }
02476         
02477         for (k = 0; k < nx; k++) {
02478             weights[k] = iffu[k] < 0.0 ? 
02479             0.0 : iffu[k] * iffu[k] / (max * max);
02480         }
02481         
02482         sum  = 0.0;
02483         sum2 = 0.0;
02484         for (k = 0; k < nx; k++) {
02485             sum  += weights[k] * ip_unull[k];
02486             sum2 += weights[k];
02487         }
02488 
02489         cpl_free(weights);
02490 
02491         imean = sum / sum2;
02492 
02493         mean_unull += (imean - mean_unull) / (j + 1.0);
02494         }
02495     }
02496 
02497     cpl_image_delete(correct_im);
02498 
02499     if (dfs_save_image(frameset, pq_im, reduced_q_tag, header, 
02500                parlist, recipe, version))
02501         fors_pmos_extract_exit(NULL);
02502 
02503     if (dfs_save_image(frameset, pu_im, reduced_u_tag, header, 
02504                parlist, recipe, version))
02505         fors_pmos_extract_exit(NULL);
02506 
02507     if (dfs_save_image(frameset, pl_im, reduced_l_tag, header, 
02508                parlist, recipe, version))
02509         fors_pmos_extract_exit(NULL);
02510 
02511     if (nscience / 4 > 1) {
02512         char *pipefile; 
02513             char *keyname;
02514         cpl_propertylist *qheader = dfs_load_header(frameset, 
02515                                                         science_tag, 0);
02516 
02517             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02518             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02519             cpl_propertylist_update_double(qheader, "CRVAL1", 
02520                                startwavelength + dispersion/2);
02521             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02522             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02523                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02524             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02525             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02526             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02527             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02528             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02529             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02530 
02531         fors_qc_start_group(qheader, "2.0", instrume);
02532 
02533         /*
02534          * QC1 group header
02535          */
02536 
02537         if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag,
02538                      "Product category", instrume))
02539         fors_pmos_extract_exit("Cannot write product category to "
02540                      "QC log file");
02541 
02542         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02543                        "DPR type", instrume))
02544         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02545                      "lamp header");
02546 
02547         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02548                        "Template", instrume))
02549         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02550                      "lamp header");
02551 
02552         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02553                        "Grism name", instrume))
02554         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02555                      "lamp header");
02556 
02557         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02558                        "Grism identifier", instrume))
02559         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02560                      "lamp header");
02561 
02562         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02563         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02564                        "Filter name", instrume);
02565 
02566         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02567                        "Collimator name", instrume))
02568         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02569                      "lamp header");
02570 
02571         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02572                        "Chip identifier", instrume))
02573         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02574                      "lamp header");
02575 
02576         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02577                        "Archive name of input data", 
02578                        instrume))
02579         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02580                      "lamp header");
02581 
02582         pipefile = dfs_generate_filename_tfits(reduced_nul_q_tag);
02583         if (fors_qc_write_string("PIPEFILE", pipefile,
02584                      "Pipeline product name", instrume))
02585         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02586         cpl_free(pipefile); pipefile = NULL;
02587 
02588 
02589         /*
02590          * QC1 parameters
02591          */
02592 
02593         keyname = "QC.NULL.Q.MEAN";
02594             
02595         if (fors_qc_write_qc_double(qheader, mean_qnull,
02596                     keyname, NULL,
02597                     "Mean Q null parameter",
02598                     instrume)) {
02599         fors_pmos_extract_exit("Cannot write mean Q null parameter "
02600                      "to QC log file");
02601         }
02602 
02603         fors_qc_end_group();
02604 
02605         if (dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader, 
02606                    parlist, recipe, version))
02607         fors_pmos_extract_exit(NULL);
02608 
02609         cpl_propertylist_delete(qheader);
02610 
02611         qheader = dfs_load_header(frameset, science_tag, 0);
02612 
02613             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02614             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02615             cpl_propertylist_update_double(qheader, "CRVAL1", 
02616                                startwavelength + dispersion/2);
02617             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02618             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02619                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02620             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02621             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02622             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02623             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02624             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02625             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02626 
02627         fors_qc_start_group(qheader, "2.0", instrume);
02628 
02629         /*
02630          * QC1 group header
02631          */
02632 
02633         if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag,
02634                      "Product category", instrume))
02635         fors_pmos_extract_exit("Cannot write product category to "
02636                      "QC log file");
02637 
02638         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02639                        "DPR type", instrume))
02640         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02641                      "lamp header");
02642 
02643         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02644                        "Template", instrume))
02645         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02646                      "lamp header");
02647 
02648         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02649                        "Grism name", instrume))
02650         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02651                      "lamp header");
02652 
02653         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02654                        "Grism identifier", instrume))
02655         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02656                      "lamp header");
02657 
02658         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02659         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02660                        "Filter name", instrume);
02661 
02662         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02663                        "Collimator name", instrume))
02664         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02665                      "lamp header");
02666 
02667         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02668                        "Chip identifier", instrume))
02669         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02670                      "lamp header");
02671 
02672         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02673                        "Archive name of input data", 
02674                        instrume))
02675         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02676                      "lamp header");
02677 
02678         pipefile = dfs_generate_filename_tfits(reduced_nul_u_tag);
02679         if (fors_qc_write_string("PIPEFILE", pipefile,
02680                      "Pipeline product name", instrume))
02681         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02682         cpl_free(pipefile); pipefile = NULL;
02683 
02684 
02685         /*
02686          * QC1 parameters
02687          */
02688 
02689         keyname = "QC.NULL.U.MEAN";
02690             
02691         if (fors_qc_write_qc_double(qheader, mean_unull,
02692                     keyname, NULL,
02693                     "Mean U null parameter",
02694                     instrume)) {
02695         fors_pmos_extract_exit("Cannot write mean U null parameter "
02696                      "to QC log file");
02697         }
02698 
02699         fors_qc_end_group();
02700 
02701         if (dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader, 
02702                    parlist, recipe, version))
02703         fors_pmos_extract_exit(NULL);
02704 
02705         cpl_propertylist_delete(qheader);
02706     }
02707 
02708     if (dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header, 
02709                parlist, recipe, version))
02710         fors_pmos_extract_exit(NULL);
02711 
02712     if (dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header, 
02713                parlist, recipe, version))
02714         fors_pmos_extract_exit(NULL);
02715 
02716     if (dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header, 
02717                parlist, recipe, version))
02718         fors_pmos_extract_exit(NULL);
02719 
02720     if (dfs_save_image(frameset, pang_im, reduced_angle_tag, header, 
02721                parlist, recipe, version))
02722         fors_pmos_extract_exit(NULL);
02723 
02724     if (dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag, 
02725                header, parlist, recipe, version))
02726         fors_pmos_extract_exit(NULL);
02727 
02728     cpl_image_delete(pq_im);
02729     cpl_image_delete(pu_im);
02730     cpl_image_delete(pl_im);
02731 
02732     cpl_image_delete(pqnull_im);
02733     cpl_image_delete(punull_im);
02734 
02735     cpl_image_delete(pqerr_im);
02736     cpl_image_delete(puerr_im);
02737     cpl_image_delete(plerr_im);
02738     cpl_image_delete(pang_im);
02739     cpl_image_delete(pangerr_im);
02740     }
02741 
02742     cpl_propertylist_delete(header);
02743 
02744     /* End of Stokes computation */
02745 
02746     for (j = 0; j < nscience; j++) {
02747     cpl_image_delete(reduceds[j]);
02748     cpl_image_delete(rerrors[j]);
02749     cpl_table_delete(slitss[j]);
02750     cpl_image_delete(mappeds[j]);
02751     }
02752 
02753     cpl_free(reduceds);
02754     cpl_free(rerrors);
02755     cpl_free(slitss);
02756     cpl_free(mappeds);
02757 
02758     cpl_free(instrume); instrume = NULL;
02759 
02760     cpl_free(skylocalmaps);
02761     cpl_free(nobjs_per_slit);
02762 
02763     if (cpl_error_get_code()) {
02764         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
02765         fors_pmos_extract_exit(NULL);
02766     }
02767     else 
02768         return 0;
02769 }
02770 
02771 /*----------------------------------------------------------------------------*/
02782 /*----------------------------------------------------------------------------*/
02783 static float * fors_check_angles(cpl_frameset * frameset,
02784                  int pmos, const char *tag, int * circ)
02785 {
02786     float     *angles  = NULL;
02787     cpl_frame *c_frame = NULL;
02788     char      *ret_id  = NULL;
02789 
02790     int i = 0;
02791 
02792     angles = cpl_malloc(sizeof(float) * pmos);
02793 
02794     for (c_frame  = cpl_frameset_find(frameset, tag);
02795      c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
02796 
02797         cpl_propertylist * header =
02798         cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
02799     
02800     if (!ret_id) {
02801         ret_id = cpl_strdup(cpl_propertylist_get_string(header, 
02802                                                         "ESO INS OPTI4 ID"));
02803 
02804         if (ret_id[1] != '5' && ret_id[1] != '4') {
02805         cpl_msg_error(cpl_func, 
02806                   "Unknown retarder plate id: %s", ret_id);
02807         return NULL;
02808         }
02809     } else {
02810         char * c_ret_id = (char *)
02811         cpl_propertylist_get_string(header, "ESO INS OPTI4 ID");
02812         if (ret_id[1] != c_ret_id[1]) {
02813         cpl_msg_error(cpl_func, "Input frames are not from the same "
02814                   "retarder plate");
02815         return NULL;
02816         }
02817     }
02818     
02819     if (ret_id[1] == '5') {  /* Linear polarimetry */
02820         angles[i] = (float)
02821         cpl_propertylist_get_double(header, "ESO INS RETA2 ROT");
02822         *circ = 0;
02823     } else {                 /* Circular polarimetry */
02824         angles[i] = (float)
02825         cpl_propertylist_get_double(header, "ESO INS RETA4 ROT");
02826         *circ = 1;
02827     }
02828 
02829         cpl_propertylist_delete(header);
02830     i++;
02831     }
02832 
02833     cpl_free(ret_id);
02834 
02835     if (*circ) {
02836     if (pmos != 2 && pmos != 4) {
02837         cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02838                           "found, but either 2 or 4 are required for "
02839                           "circular polarization measurements!", pmos);
02840         return NULL;
02841     }
02842     } else {
02843     if (pmos != 4 && pmos != 8 && pmos != 16) {
02844         cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02845                           "found, but either 4, 8, or 16 are required for "
02846                           "linear polarization measurements!", pmos);
02847         return NULL;
02848     }
02849     }
02850     
02851     /* Check completeness */
02852 
02853     if (*circ) {
02854         for (i = 0; i < pmos; i++) {
02855             if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
02856                 const char *cangles;
02857                 switch (pmos) {
02858                 case 2: cangles  = "-45.0, 45.0"; break;
02859                 case 4: cangles  = "-45.0, 45.0, 135.0, 225.0"; break;
02860                 default: assert(0);
02861                 }  
02862 
02863             cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02864                               "angle %.2f. All angles %s must be provided.",
02865                               angles[i], cangles);
02866                 return NULL;
02867             }
02868         }
02869     }
02870     else {
02871         for (i = 0; i < pmos; i++) {
02872             if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
02873                 const char *cangles;
02874                 switch (pmos) {
02875                 case 4: cangles  = "0.0, 22.5, 45.0, 67.5"; break;
02876                 case 8: cangles  = "0.0, 22.5, 45.0, 67.5, "
02877                                    "90.0, 112.5, 135.0, 157.5"; break;
02878                 case 16: cangles = "0.0, 22.5, 45.0, 67.5, "
02879                                    "90.0, 112.5, 135.0, 157.5, "
02880                                    "180.0, 202.5, 225.0, 247.5, "
02881                                    "270.0, 292.5, 315.0, 337.5"; break;
02882                 default: assert(0);
02883                 }  
02884 
02885             cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02886                               "angle %.2f. All angles %s must be provided.",
02887                               angles[i], cangles);
02888                 return NULL;
02889             }
02890         }
02891     }
02892 
02893     return angles;
02894 }
02895 
02896 /*----------------------------------------------------------------------------*/
02904 /*----------------------------------------------------------------------------*/
02905 static int
02906 fors_find_angle_pos(float * angles, int nangles, float angle)
02907 {
02908     int i, match = 0;
02909 
02910     for (i = 0; i < nangles; i++) {
02911     if (fabs(angles[i]         - angle) < 1.0 || 
02912         fabs(angles[i] - 360.0 - angle) < 1.0) {
02913         match = 1;
02914         break;
02915     }
02916     }
02917 
02918     return match ? i : -1;
02919 }

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