fors_pmos_extract.c

00001 /* $Id: fors_pmos_extract.c,v 1.10 2013-10-09 15:59:38 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2013-10-09 15:59:38 $
00024  * $Revision: 1.10 $
00025  * $Name: not supported by cvs2svn $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <string.h>
00034 #include <ctype.h>
00035 #include <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 ((const char *)message != NULL) 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 ((const char *)message != NULL) 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;
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     int   nslits_out_det = 0;
00684 
00685 
00686     snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00687 
00688     cpl_msg_set_indentation(2);
00689 
00690     /* 
00691      * Get configuration parameters
00692      */
00693 
00694     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00695     cpl_msg_indent_more();
00696 
00697     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00698         fors_pmos_extract_exit("Too many in input: GRISM_TABLE");
00699 
00700     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00701 
00702     dispersion = dfs_get_parameter_double(parlist, 
00703                     "fors.fors_pmos_extract.dispersion", grism_table);
00704 
00705     if (dispersion <= 0.0)
00706         fors_pmos_extract_exit("Invalid resampling step");
00707 
00708     skyalign = dfs_get_parameter_int(parlist, 
00709                     "fors.fors_pmos_extract.skyalign", NULL);
00710 
00711     if (skyalign > 2)
00712         fors_pmos_extract_exit("Max polynomial degree for sky alignment is 2");
00713 
00714     wcolumn = dfs_get_parameter_string(parlist, 
00715                     "fors.fors_pmos_extract.wcolumn", NULL);
00716 
00717     startwavelength = dfs_get_parameter_double(parlist, 
00718                     "fors.fors_pmos_extract.startwavelength", grism_table);
00719     if (startwavelength < 3000.0 || startwavelength > 13000.0)
00720         fors_pmos_extract_exit("Invalid wavelength");
00721 
00722     endwavelength = dfs_get_parameter_double(parlist, 
00723                     "fors.fors_pmos_extract.endwavelength", grism_table);
00724     if (endwavelength < 3000.0 || endwavelength > 13000.0)
00725         fors_pmos_extract_exit("Invalid wavelength");
00726 
00727     if (endwavelength - startwavelength <= 0.0)
00728         fors_pmos_extract_exit("Invalid wavelength interval");
00729 
00730     flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flux", NULL);
00731 
00732     flatfield = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flatfield", 
00733                                        NULL);
00734 
00735     skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skyglobal", 
00736                                        NULL);
00737     skylocal  = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skylocal", 
00738                                        NULL);
00739     skymedian = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skymedian", 
00740                                        NULL);
00741 /* NSS
00742     skymedian = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.skymedian", 
00743                                        NULL);
00744 */
00745     
00746     chromatism = 
00747     dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.chromatism", 
00748                    NULL);
00749 
00750     if (skylocal && skyglobal)
00751         fors_pmos_extract_exit("Cannot apply both local and global sky subtraction");
00752 
00753     if (skylocal && skymedian)
00754         fors_pmos_extract_exit("Cannot apply sky subtraction both on extracted "
00755                           "and non-extracted spectra");
00756 
00757     cosmics = dfs_get_parameter_bool(parlist, 
00758                                      "fors.fors_pmos_extract.cosmics", NULL);
00759 
00760     if (cosmics)
00761         if (!(skyglobal || skylocal))
00762             fors_pmos_extract_exit("Cosmic rays correction requires "
00763                               "either skylocal=true or skyglobal=true");
00764 
00765     slit_margin = dfs_get_parameter_int(parlist, 
00766                                         "fors.fors_pmos_extract.slit_margin",
00767                                         NULL);
00768     if (slit_margin < 0)
00769         fors_pmos_extract_exit("Value must be zero or positive");
00770 
00771     ext_radius = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_radius",
00772                                        NULL);
00773     if (ext_radius < 0)
00774         fors_pmos_extract_exit("Value must be zero or positive");
00775 
00776     cont_radius = dfs_get_parameter_int(parlist, 
00777                                         "fors.fors_pmos_extract.cont_radius",
00778                                         NULL);
00779     if (cont_radius < 0)
00780         fors_pmos_extract_exit("Value must be zero or positive");
00781 
00782     ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_mode",
00783                                        NULL);
00784     if (ext_mode < 0 || ext_mode > 1)
00785         fors_pmos_extract_exit("Invalid object extraction mode");
00786 
00787     time_normalise = dfs_get_parameter_bool(parlist, 
00788                              "fors.fors_pmos_extract.time_normalise", NULL);
00789 
00790     check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.check", NULL);
00791     cpl_table_delete(grism_table); grism_table = NULL;
00792 
00793     if (cpl_error_get_code())
00794         fors_pmos_extract_exit("Failure getting the configuration parameters");
00795 
00796     
00797     /* 
00798      * Check input set-of-frames
00799      */
00800 
00801     cpl_msg_indent_less();
00802     cpl_msg_info(recipe, "Check input set-of-frames:");
00803     cpl_msg_indent_more();
00804 
00805     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00806         cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00807 
00808     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00809         cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00810 
00811     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00812         cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00813 
00814     standard = 0;
00815     pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS");
00816 
00817     if (pmos == 0) {
00818         pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS");
00819         standard = 1;
00820     }
00821 
00822     if (pmos == 0)
00823         fors_pmos_extract_exit("Missing input scientific frame");
00824 
00825     angles = fors_check_angles(frameset, pmos, 
00826                                 standard ? "STANDARD_PMOS" : "SCIENCE_PMOS", 
00827                                 &circ);
00828     if (angles == NULL)
00829         fors_pmos_extract_exit("Polarization angles could not be read");
00830 
00831     if (circ)
00832         chromatism = 0; /* Chromatism correction unrequired for 
00833                            circular polarimetry */
00834 
00835 
00836     nscience = pmos;
00837 
00838     reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00839     rerrors  = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00840     slitss   = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
00841     mappeds  = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00842     skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00843 
00844     if (pmos) {
00845         cpl_msg_info(recipe, "PMOS data found");
00846         if (standard) {
00847             science_tag             = "STANDARD_PMOS";
00848             reduced_science_tag     = "REDUCED_STD_PMOS";
00849             unmapped_science_tag    = "UNMAPPED_STD_PMOS";
00850             mapped_science_tag      = "MAPPED_STD_PMOS";
00851             mapped_science_sky_tag  = "MAPPED_ALL_STD_PMOS";
00852             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_STD_PMOS";
00853             wavelength_map_sky_tag  = "WAVELENGTH_MAP_STD_PMOS";
00854             disp_coeff_sky_tag      = "DISP_COEFF_STD_PMOS";
00855             mapped_sky_tag          = "MAPPED_SKY_STD_PMOS";
00856             unmapped_sky_tag        = "UNMAPPED_SKY_STD_PMOS";
00857             object_table_tag        = "OBJECT_TABLE_STD_PMOS";
00858             object_table_pol_tag    = "OBJECT_TABLE_POL_STD_PMOS";
00859             reduced_sky_tag         = "REDUCED_SKY_STD_PMOS";
00860             reduced_error_tag       = "REDUCED_ERROR_STD_PMOS";
00861             reduced_q_tag           = "REDUCED_Q_STD_PMOS";
00862             reduced_u_tag           = "REDUCED_U_STD_PMOS";
00863             reduced_v_tag           = "REDUCED_V_STD_PMOS";
00864             reduced_l_tag           = "REDUCED_L_STD_PMOS";
00865             reduced_error_q_tag     = "REDUCED_ERROR_Q_STD_PMOS";
00866             reduced_error_u_tag     = "REDUCED_ERROR_U_STD_PMOS";
00867             reduced_error_v_tag     = "REDUCED_ERROR_V_STD_PMOS";
00868             reduced_error_l_tag     = "REDUCED_ERROR_L_STD_PMOS";
00869             reduced_nul_q_tag       = "REDUCED_NUL_Q_STD_PMOS";
00870             reduced_nul_u_tag       = "REDUCED_NUL_U_STD_PMOS";
00871             reduced_nul_v_tag       = "REDUCED_NUL_V_STD_PMOS";
00872             reduced_angle_tag       = "REDUCED_ANGLE_STD_PMOS";
00873             reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS";
00874         }
00875         else {
00876             science_tag             = "SCIENCE_PMOS";
00877             reduced_science_tag     = "REDUCED_SCI_PMOS";
00878             unmapped_science_tag    = "UNMAPPED_SCI_PMOS";
00879             mapped_science_tag      = "MAPPED_SCI_PMOS";
00880             mapped_science_sky_tag  = "MAPPED_ALL_SCI_PMOS";
00881             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_SCI_PMOS";
00882             wavelength_map_sky_tag  = "WAVELENGTH_MAP_SCI_PMOS";
00883             disp_coeff_sky_tag      = "DISP_COEFF_SCI_PMOS";
00884             mapped_sky_tag          = "MAPPED_SKY_SCI_PMOS";
00885             unmapped_sky_tag        = "UNMAPPED_SKY_SCI_PMOS";
00886             object_table_tag        = "OBJECT_TABLE_SCI_PMOS";
00887             object_table_pol_tag    = "OBJECT_TABLE_POL_SCI_PMOS";
00888             reduced_sky_tag         = "REDUCED_SKY_SCI_PMOS";
00889             reduced_error_tag       = "REDUCED_ERROR_SCI_PMOS";
00890             reduced_q_tag           = "REDUCED_Q_SCI_PMOS";
00891             reduced_u_tag           = "REDUCED_U_SCI_PMOS";
00892             reduced_v_tag           = "REDUCED_V_SCI_PMOS";
00893             reduced_l_tag           = "REDUCED_L_SCI_PMOS";
00894             reduced_error_q_tag     = "REDUCED_ERROR_Q_SCI_PMOS";
00895             reduced_error_u_tag     = "REDUCED_ERROR_U_SCI_PMOS";
00896             reduced_error_v_tag     = "REDUCED_ERROR_V_SCI_PMOS";
00897             reduced_error_l_tag     = "REDUCED_ERROR_L_SCI_PMOS";
00898             reduced_nul_q_tag       = "REDUCED_NUL_Q_SCI_PMOS";
00899             reduced_nul_u_tag       = "REDUCED_NUL_U_SCI_PMOS";
00900             reduced_nul_v_tag       = "REDUCED_NUL_V_SCI_PMOS";
00901             reduced_angle_tag       = "REDUCED_ANGLE_SCI_PMOS";
00902             reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS";
00903         }
00904 
00905         master_norm_flat_tag    = "MASTER_NORM_FLAT_PMOS";
00906         global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_PMOS";
00907 
00908         if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
00909             master_norm_flat_tag    = "MASTER_NORM_FLAT_LONG_PMOS";
00910         }
00911     }
00912 
00913     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
00914         fors_pmos_extract_exit("Missing required input: MASTER_BIAS");
00915 
00916     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00917         fors_pmos_extract_exit("Too many in input: MASTER_BIAS");
00918 
00919     if (skyalign >= 0)
00920         if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
00921             fors_pmos_extract_exit("Too many in input: MASTER_SKYLINECAT");
00922 
00923     if (chromatism) {
00924     if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) {
00925         cpl_msg_error(recipe, "Missing required input: %s",
00926               chrom_table_tag);
00927         fors_pmos_extract_exit(NULL);
00928     }
00929 
00930     if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) {
00931         cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag);
00932         fors_pmos_extract_exit(NULL);
00933     }
00934     }
00935 
00936     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
00937         if (flatfield) {
00938             cpl_msg_error(recipe, "Too many in input: %s", 
00939                           master_norm_flat_tag);
00940             fors_pmos_extract_exit(NULL);
00941         }
00942         else {
00943             cpl_msg_warning(recipe, "%s in input are ignored, "
00944                             "since flat field correction was not requested", 
00945                             master_norm_flat_tag);
00946         }
00947     }
00948 
00949     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
00950         if (!flatfield) {
00951             cpl_msg_warning(recipe, "%s in input is ignored, "
00952                             "since flat field correction was not requested", 
00953                             master_norm_flat_tag);
00954         }
00955     }
00956 
00957     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
00958         if (flatfield) {
00959             cpl_msg_error(recipe, "Flat field correction was requested, "
00960                           "but no %s are found in input",
00961                           master_norm_flat_tag);
00962             fors_pmos_extract_exit(NULL);
00963         }
00964     }
00965 
00966     if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0)
00967         fors_pmos_extract_exit("Missing required input: MASTER_DISTORTION_TABLE");
00968     
00969     if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1)
00970     fors_pmos_extract_exit("Too many in input: MASTER_DISTORTION_TABLE");
00971     
00972     global = dfs_load_table(frameset, master_distortion_tag, 1);
00973     if (global == NULL)
00974     fors_pmos_extract_exit("Cannot load master distortion table");
00975     
00976     cpl_msg_indent_less();
00977 
00978     /*
00979      * Get the reference wavelength and the rebin factor along the
00980      * dispersion direction from a scientific exposure
00981      */
00982 
00983     header = dfs_load_header(frameset, science_tag, 0);
00984 
00985     if (header == NULL)
00986         fors_pmos_extract_exit("Cannot load scientific frame header");
00987 
00988     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00989     if (instrume == NULL)
00990         fors_pmos_extract_exit("Missing keyword INSTRUME in scientific header");
00991     instrume = cpl_strdup(instrume);
00992 
00993     if (instrume[4] == '1')
00994         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00995     if (instrume[4] == '2')
00996         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00997 
00998     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00999 
01000     if (cpl_error_get_code() != CPL_ERROR_NONE)
01001         fors_pmos_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific "
01002                         "frame header");
01003 
01004     if (reference < 3000.0)   /* Perhaps in nanometers... */
01005         reference *= 10;
01006 
01007     if (reference < 3000.0 || reference > 13000.0) {
01008         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01009                       "keyword ESO INS GRIS1 WLEN in scientific frame header",
01010                       reference);
01011         fors_pmos_extract_exit(NULL);
01012     }
01013 
01014     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01015 
01016     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01017 
01018     if (cpl_error_get_code() != CPL_ERROR_NONE)
01019         fors_pmos_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific "
01020                         "frame header");
01021 
01022     if (rebin != 1) {
01023         dispersion *= rebin;
01024         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01025                         "resampling step used is %f A/pixel", rebin, 
01026                         dispersion);
01027     }
01028 
01029     gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01030 
01031     if (cpl_error_get_code() != CPL_ERROR_NONE)
01032         fors_pmos_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific "
01033                           "frame header");
01034 
01035     cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01036 
01037     ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01038 
01039     if (cpl_error_get_code() != CPL_ERROR_NONE)
01040         fors_pmos_extract_exit("Missing keyword ESO DET OUT1 RON in scientific "
01041                           "frame header");
01042 
01043     ron /= gain;     /* Convert from electrons to ADU */
01044 
01045     cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
01046 
01047     cpl_msg_info(recipe, "Load normalised flat field (if present)...");
01048     cpl_msg_indent_more();
01049 
01050     if (flatfield) {
01051     norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 
01052                    CPL_TYPE_FLOAT, 0, 1);
01053     }
01054 
01055     cpl_msg_info(recipe, "Produce mask slit position table...");
01056 
01057     maskslits = mos_load_slits_fors_pmos(header, &nslits_out_det);
01058 
01059     if (skyalign >= 0) {
01060 
01061     cpl_msg_indent_less();
01062     cpl_msg_info(recipe, "Load input sky line catalog...");
01063     cpl_msg_indent_more();
01064 
01065     wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
01066 
01067     if (wavelengths) {
01068         /*
01069          * Cast the wavelengths into a (double precision) CPL vector
01070          */
01071 
01072         nlines = cpl_table_get_nrow(wavelengths);
01073 
01074         if (nlines == 0)
01075         fors_pmos_extract_exit("Empty input sky line catalog");
01076 
01077         if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01078         cpl_msg_error(recipe, "Missing column %s in input line "
01079                   "catalog table", wcolumn);
01080         fors_pmos_extract_exit(NULL);
01081         }
01082 
01083         line = cpl_malloc(nlines * sizeof(double));
01084     
01085         for (i = 0; i < nlines; i++)
01086         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01087 
01088         cpl_table_delete(wavelengths); wavelengths = NULL;
01089 
01090         lines = cpl_vector_wrap(nlines, line);
01091     }
01092     else {
01093         cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
01094     }
01095     }
01096 
01097 
01098     cpl_propertylist_delete(header); header = NULL;
01099 
01100     /*
01101      * Load the wavelength calibration table
01102      */
01103 
01104     for (j = 0; j < nscience; j++) {
01105     int k;
01106 
01107     cpl_msg_indent_less();
01108     cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f "
01109              "(%d out of %d) ...",
01110              angles[j], j + 1, nscience);
01111     cpl_msg_indent_more();
01112 
01113     cpl_msg_info(recipe, "Load scientific exposure...");
01114     cpl_msg_indent_more();
01115 
01116     /*
01117      * FIXME: Horrible workaround to avoid the problem because of the
01118      * multiple encapsulation of cpl_frameset_find() in different 
01119      * loading functions
01120      */
01121 
01122     header = dfs_load_header(frameset, science_tag, 0);
01123 
01124     for (k = 0; k < j; k ++) {
01125         cpl_propertylist_delete(header);
01126         header = dfs_load_header(frameset, NULL, 0);
01127     }
01128 
01129     spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
01130 
01131     for (k = 0; k < j; k ++) {
01132         cpl_image_delete(spectra);
01133         spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01134     }
01135 
01136     if (spectra == NULL)
01137         fors_pmos_extract_exit("Cannot load scientific frame");
01138         
01139     if (header == NULL)
01140         fors_pmos_extract_exit("Cannot load scientific frame header");
01141 
01142     alltime = cpl_propertylist_get_double(header, "EXPTIME");
01143 
01144     if (cpl_error_get_code() != CPL_ERROR_NONE)
01145         fors_pmos_extract_exit("Missing keyword EXPTIME in scientific "
01146                    "frame header");
01147 
01148     /* Leave the header on for the next step... */
01149     //cpl_propertylist_delete(header); header = NULL;
01150 
01151     cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 
01152              alltime);
01153 
01154     cpl_msg_indent_less();
01155 
01156     /*
01157      * Remove the master bias
01158      */
01159 
01160     cpl_msg_info(recipe, "Remove the master bias...");
01161 
01162     bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
01163 
01164     if (bias == NULL)
01165         fors_pmos_extract_exit("Cannot load master bias");
01166 
01167     overscans = mos_load_overscans_vimos(header, 1);
01168 
01169     dummy = mos_remove_bias(spectra, bias, overscans);
01170     cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
01171     cpl_image_delete(bias); bias = NULL;
01172     cpl_table_delete(overscans); overscans = NULL;
01173 
01174     if (spectra == NULL)
01175         fors_pmos_extract_exit("Cannot remove bias from scientific frame");
01176 
01177     ccd_xsize = nx = cpl_image_get_size_x(spectra);
01178     ny = cpl_image_get_size_y(spectra);
01179 
01180     if (flatfield) {
01181 
01182         if (norm_flat) {
01183         cpl_msg_info(recipe, "Apply flat field correction...");
01184         if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
01185             cpl_msg_error(recipe, "Failure of flat field correction: %s",
01186                   cpl_error_get_message());
01187             fors_pmos_extract_exit(NULL);
01188         }
01189         }
01190         else {
01191         cpl_msg_error(recipe, "Cannot load input %s for flat field "
01192                   "correction", master_norm_flat_tag);
01193         fors_pmos_extract_exit(NULL);
01194         }
01195 
01196     }
01197 
01198     /*
01199      * Load the slit location table
01200      */
01201 
01202     slits = mos_build_slit_location(global, maskslits, ny);
01203 
01204     if (slits == NULL) {
01205         fors_pmos_extract_exit("Cannot load slits location table");
01206     } else {
01207         cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT);
01208 
01209         int m, null, size = cpl_table_get_nrow(slits);
01210 
01211         for (m = 0; m < size; m++) {
01212         int slit_id = cpl_table_get(slits, "slit_id", m, &null);
01213 
01214         int pair_id = slit_id % 2 ? slit_id + 1 : slit_id;
01215 
01216         cpl_table_set(slits, "pair_id", m, pair_id);
01217         }
01218     }
01219     
01220     cpl_msg_info(recipe, "Processing scientific spectra...");
01221 
01222     /*
01223      * Load the spectral curvature table
01224      */
01225 
01226     polytraces = mos_build_curv_coeff(global, maskslits, slits);
01227     if (polytraces == NULL)
01228         fors_pmos_extract_exit("Cannot create spectral curvature table");
01229  
01230     /*
01231      * This one will also generate the spatial map from the spectral 
01232      * curvature table (in the case of multislit data)
01233      */
01234 
01235     coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01236 
01237     smapped = mos_spatial_calibration(spectra, slits, polytraces, reference,
01238                       startwavelength, endwavelength,
01239                       dispersion, flux, coordinate);
01240 
01241     /*
01242      * Generate a rectified wavelength map from the wavelength calibration 
01243      * table
01244      */
01245 
01246     /*
01247      * Load the wavelength calibration table
01248      */
01249  
01250     idscoeff = mos_build_disp_coeff(global, slits);
01251     if (idscoeff == NULL)
01252         fors_pmos_extract_exit("Cannot create wavelength calibration table");
01253 
01254     rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 
01255                    endwavelength);
01256 
01257     if (dispersion > 1.0)
01258         highres = 0;
01259     else
01260         highres = 1;
01261 
01262     if (skyalign >= 0) {
01263         if (skyalign) {
01264         cpl_msg_info(recipe, "Align wavelength solution to reference "
01265                  "skylines applying %d order residual fit...", skyalign);
01266         }
01267         else {
01268         cpl_msg_info(recipe, "Align wavelength solution to reference "
01269                  "skylines applying median offset...");
01270         }
01271 
01272         if (!j) {
01273         offsets = mos_wavelength_align(smapped, slits, reference, 
01274                            startwavelength, endwavelength, 
01275                            idscoeff, lines, highres, 
01276                            skyalign, rainbow, 4);
01277 
01278         if (offsets) {
01279             if (standard)
01280             cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01281                     "to reference sky lines may be unreliable in "
01282                     "this case!");
01283 
01284             if (dfs_save_table(frameset, offsets, skylines_offsets_tag,
01285                        NULL, parlist, recipe, version)) {
01286             fors_pmos_extract_exit(NULL);
01287             }
01288 
01289         } else {
01290             cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01291                     "to reference sky lines could not be done!");
01292             skyalign = -1;
01293         }
01294         }
01295 
01296 
01297     }
01298 
01299     wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 
01300                       polytraces, reference, 
01301                       startwavelength, endwavelength,
01302                       dispersion);
01303 
01304 
01305     cpl_image_delete(rainbow); rainbow = NULL;
01306     cpl_image_delete(coordinate); coordinate = NULL;
01307 
01308     /*
01309      * Here the wavelength calibrated slit spectra are created. This frame
01310      * contains sky_science.
01311      */
01312 
01313     mapped_sky = mos_wavelength_calibration(smapped, reference,
01314                         startwavelength, endwavelength,
01315                         dispersion, idscoeff, flux);
01316 
01317     if (!j) {
01318         cpl_msg_indent_less();
01319         cpl_msg_info(recipe, "Check applied wavelength against skylines...");
01320         cpl_msg_indent_more();
01321 
01322         mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength,
01323                        dispersion, 6, highres);
01324 
01325 
01326         cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
01327 
01328         mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01329 
01330         cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
01331              mean_rms, mean_rms * dispersion);
01332     }
01333 
01334     save_header = cpl_propertylist_duplicate(header);
01335 
01336     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01337     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01338     cpl_propertylist_update_double(header, "CRVAL1", 
01339                        startwavelength + dispersion/2);
01340     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01341     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01342        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01343     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01344     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01345     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01346     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01347     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01348     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01349 
01350     if (time_normalise) {
01351         dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
01352         if (!j) {
01353         if(dfs_save_image_null(frameset, parlist,
01354                        mapped_science_sky_tag,
01355                        recipe, version)) {
01356             fors_pmos_extract_exit(NULL);
01357         }
01358         }
01359         if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) {
01360         fors_pmos_extract_exit(NULL);
01361         }
01362         cpl_image_delete(dummy); dummy = NULL;
01363     }
01364     else {
01365 
01366         if (!j) {
01367         if(dfs_save_image_null(frameset, parlist,
01368                        mapped_science_sky_tag,
01369                        recipe, version)) {
01370             fors_pmos_extract_exit(NULL);
01371         }
01372         }
01373 
01374         if (dfs_save_image_ext(mapped_sky,
01375                    mapped_science_sky_tag, header)) {
01376         fors_pmos_extract_exit(NULL);
01377         }
01378 
01379     }
01380 
01381 /*    if (skyglobal == 0 && skymedian < 0) {    NSS */
01382     if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
01383         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01384     }
01385 
01386     if (skyglobal || skylocal) {
01387 
01388         cpl_msg_indent_less();
01389 
01390         if (skyglobal) {
01391         cpl_msg_info(recipe, "Global sky determination...");
01392         cpl_msg_indent_more();
01393         skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01394 
01395         sky = mos_sky_map_super(spectra, wavemap, dispersion, 
01396                     2.0, 50, skymap);
01397 
01398         if (sky) {
01399             cpl_image_subtract(spectra, skymap);
01400         }
01401         else {
01402             cpl_image_delete(skymap); skymap = NULL;
01403         }
01404         }
01405         else {
01406         cpl_msg_info(recipe, "Local sky determination...");
01407         cpl_msg_indent_more();
01408         skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
01409                       startwavelength, endwavelength, dispersion);
01410         }
01411 
01412         if (skymap) {
01413         if (skyglobal) {
01414             if (time_normalise)
01415             cpl_table_divide_scalar(sky, "sky", alltime);
01416 
01417 /* Old saving:
01418 
01419             if (!j) {
01420             if (dfs_save_table(frameset, sky,
01421                        global_sky_spectrum_tag, 
01422                        NULL, parlist, recipe, version)) {
01423                 fors_pmos_extract_exit(NULL);
01424             }
01425             } else {
01426             if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 
01427                            NULL)) {
01428                 fors_pmos_extract_exit(NULL);
01429             }
01430             }
01431 
01432 End of old saving */
01433 
01434                     if (!j) {
01435                         if(dfs_save_image_null(frameset, parlist, 
01436                                                global_sky_spectrum_tag,
01437                                                recipe, version)) {
01438                 fors_pmos_extract_exit(NULL);
01439                         }
01440                     }
01441     
01442                     if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 
01443                                            NULL)) {
01444                         fors_pmos_extract_exit(NULL);
01445                     }
01446     
01447     
01448             cpl_table_delete(sky); sky = NULL;
01449         }
01450 
01451 //      save_header = dfs_load_header(frameset, science_tag, 0);
01452 
01453         if (time_normalise)
01454             cpl_image_divide_scalar(skymap, alltime);
01455 
01456         if (!j) {
01457             if(dfs_save_image_null(frameset, parlist,
01458                        unmapped_sky_tag,
01459                        recipe, version)) {
01460             fors_pmos_extract_exit(NULL);
01461             }
01462         }
01463 
01464         if (dfs_save_image_ext(skymap, unmapped_sky_tag,
01465                        save_header)) {
01466             fors_pmos_extract_exit(NULL);
01467         }
01468 
01469         cpl_image_delete(skymap); skymap = NULL;
01470 
01471         if (!j) {
01472             if(dfs_save_image_null(frameset, parlist,
01473                        unmapped_science_tag,
01474                        recipe, version)) {
01475             fors_pmos_extract_exit(NULL);
01476             }
01477         }
01478 
01479         if (dfs_save_image_ext(spectra, unmapped_science_tag,
01480                        save_header)) {
01481             fors_pmos_extract_exit(NULL);
01482         }
01483 
01484 //      cpl_propertylist_delete(save_header); save_header = NULL;
01485 
01486         if (cosmics) {
01487             cpl_msg_info(recipe, "Removing cosmic rays...");
01488             mos_clean_cosmics(spectra, gain, -1., -1.);
01489         }
01490 
01491         /*
01492          * The spatially rectified image, that contained the sky,
01493          * is replaced by a sky-subtracted spatially rectified image:
01494          */
01495 
01496         cpl_image_delete(smapped); smapped = NULL;
01497 
01498         smapped = mos_spatial_calibration(spectra, slits, polytraces, 
01499                           reference, startwavelength, 
01500                           endwavelength, dispersion, 
01501                           flux, NULL);
01502         }
01503         else {
01504         cpl_msg_warning(recipe, "Sky subtraction failure");
01505         if (cosmics)
01506             cpl_msg_warning(recipe, "Cosmic rays removal not performed!");
01507         cosmics = skylocal = skyglobal = 0;
01508         }
01509     }
01510 
01511     cpl_image_delete(spectra); spectra = NULL;
01512     cpl_table_delete(polytraces); polytraces = NULL;
01513 
01514     if (skyalign >= 0) {
01515         save_header = dfs_load_header(frameset, science_tag, 0);
01516 
01517         if (!j) {
01518         if(dfs_save_image_null(frameset, parlist,
01519                        wavelength_map_sky_tag,
01520                        recipe, version)) {
01521             fors_pmos_extract_exit(NULL);
01522         }
01523         }
01524 
01525         if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag,
01526                    save_header)) {
01527         fors_pmos_extract_exit(NULL);
01528         }
01529 
01530 //      cpl_propertylist_delete(save_header); save_header = NULL;
01531     }
01532 
01533     cpl_image_delete(wavemap); wavemap = NULL;
01534 
01535     mapped = mos_wavelength_calibration(smapped, reference,
01536                         startwavelength, endwavelength,
01537                         dispersion, idscoeff, flux);
01538 
01539     cpl_image_delete(smapped); smapped = NULL;
01540 
01541     if (skyalign >= 0) {
01542         if (!j) {
01543         if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag,
01544                    NULL, parlist, recipe, version)) {
01545             fors_pmos_extract_exit(NULL);
01546         }
01547         }
01548     }
01549 
01550 /*    if (skymedian >= 0) {    NSS */
01551     if (skymedian) {
01552             cpl_msg_indent_less();
01553             cpl_msg_info(recipe, "Local sky determination...");
01554             cpl_msg_indent_more();
01555        
01556 /*   NSS      skylocalmap = mos_sky_local(mapped, slits, skymedian); */
01557 /*            skylocalmap = mos_sky_local(mapped, slits, 0);        */
01558             skylocalmap = mos_sky_local_old(mapped, slits);       
01559             cpl_image_subtract(mapped, skylocalmap);
01560 /*
01561   if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 
01562   parlist, recipe, version))
01563   fors_pmos_extract_exit(NULL);
01564 */
01565             cpl_image_delete(skylocalmap); skylocalmap = NULL;
01566     }
01567 
01568 /*    if (skyglobal || skymedian >= 0 || skylocal) {   NSS */
01569     if (skyglobal || skymedian || skylocal) {
01570 
01571         skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
01572 
01573         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01574 
01575         if (time_normalise) {
01576         dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
01577 
01578         if (!j) {
01579             if(dfs_save_image_null(frameset, parlist,
01580                        mapped_sky_tag,
01581                        recipe, version)) {
01582             fors_pmos_extract_exit(NULL);
01583             }
01584         }
01585 
01586         if (dfs_save_image_ext(dummy, mapped_sky_tag,
01587                        header)) {
01588             fors_pmos_extract_exit(NULL);
01589         }
01590 
01591         cpl_image_delete(dummy); dummy = NULL;
01592         }
01593         else {
01594         if (!j) {
01595             if(dfs_save_image_null(frameset, parlist,
01596                        mapped_sky_tag,
01597                        recipe, version)) {
01598             fors_pmos_extract_exit(NULL);
01599             }
01600         }
01601 
01602         if (dfs_save_image_ext(skylocalmap, mapped_sky_tag,
01603                        header)) {
01604             fors_pmos_extract_exit(NULL);
01605         }
01606         }
01607 
01608         skylocalmaps[j] = skylocalmap;
01609 
01610         cpl_msg_indent_less();
01611         cpl_msg_info(recipe, "Object detection...");
01612         cpl_msg_indent_more();
01613 
01614         if (!j)
01615         origslits = cpl_table_duplicate(slits);
01616 
01617         if (cosmics || nscience > 1) {
01618         dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius, 
01619                        cont_radius);
01620         }
01621         else {
01622         mapped_cleaned = cpl_image_duplicate(mapped);
01623         mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
01624         dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 
01625                        ext_radius, cont_radius);
01626 
01627         cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
01628         }
01629 
01630         cpl_image_delete(dummy); dummy = NULL;
01631 
01632         if (check) {
01633 
01634 /* Old saving:
01635 
01636         if (!j) {
01637             if (dfs_save_table(frameset, slits, object_table_tag,
01638                        NULL, parlist, recipe, version)) {
01639             fors_pmos_extract_exit(NULL);
01640             }
01641         } else {
01642             if (dfs_save_table_ext(slits, object_table_tag, NULL)) {
01643             fors_pmos_extract_exit(NULL);
01644             }
01645         }
01646 
01647 End old saving */
01648 
01649                 if (!j) {
01650                     if(dfs_save_image_null(frameset, parlist,
01651                                            object_table_tag,
01652                                            recipe, version)) {
01653                         fors_pmos_extract_exit(NULL);
01654                     }
01655                 }
01656 
01657                 if (dfs_save_table_ext(slits, object_table_tag, NULL)) {
01658                     fors_pmos_extract_exit(NULL);
01659                 }
01660         }
01661     }
01662 
01663     slitss[j]  = slits;
01664     mappeds[j] = mapped;
01665 
01666     cpl_msg_indent_less();
01667 
01668     cpl_propertylist_delete(header); header = NULL;
01669     cpl_propertylist_delete(save_header); save_header = NULL;
01670 
01671     cpl_table_delete(idscoeff); idscoeff = NULL;
01672     }
01673 
01674     cpl_table_delete(offsets); offsets = NULL;
01675 
01676     cpl_image_delete(norm_flat); norm_flat = NULL;
01677     cpl_vector_delete(lines); lines = NULL;
01678 
01679     cpl_table_delete(maskslits); maskslits = NULL;
01680 
01681     
01682     cpl_msg_indent_less();
01683     cpl_msg_info(recipe, 
01684          "Check object detection in both beams for all angles...");
01685     cpl_msg_indent_more();
01686 
01687     /* House keeping - selection of objects for which information required 
01688        for Stokes parameters computation is present */
01689     error = mos_object_intersect(slitss, origslits, nscience, 5.0);
01690     if (error == CPL_ERROR_DATA_NOT_FOUND) {
01691         cpl_msg_warning(recipe, "No objects found: no Stokes "
01692                        "parameters to compute!");
01693         for (j = 0; j < nscience; j++)
01694             cpl_table_delete(slitss[j]);
01695         cpl_free(slitss);
01696         cpl_table_delete(origslits);
01697         return 0;
01698     } else if (error) {
01699         fors_pmos_extract_exit("Problem in polarimetric object selection");
01700     }
01701 
01702     if (dfs_save_table(frameset, origslits, object_table_pol_tag,
01703                NULL, parlist, recipe, version)) {
01704     fors_pmos_extract_exit(NULL);
01705     }
01706 
01707     nobjs_per_slit = fors_get_nobjs_perslit(origslits);
01708 
01709     cpl_msg_indent_less();
01710     cpl_msg_info(recipe, "Object extraction...");
01711     cpl_msg_indent_more();
01712 
01713     for (j = 0; j < nscience; j++) {
01714     int k;
01715 
01716     header = dfs_load_header(frameset, science_tag, 0);
01717 
01718     for (k = 0; k < j; k ++) {
01719         cpl_propertylist_delete(header);
01720         header = dfs_load_header(frameset, NULL, 0);
01721     }
01722 
01723     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01724     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01725     cpl_propertylist_update_double(header, "CRVAL1", 
01726                        startwavelength + dispersion/2);
01727     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01728     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01729        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01730     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01731     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01732     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01733     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01734     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01735     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01736 
01737     if (skyglobal || skymedian || skylocal) {
01738 
01739         cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...",
01740              angles[j], j + 1, nscience);
01741 
01742         images = mos_extract_objects(mappeds[j], NULL, skylocalmaps[j],
01743                      origslits, 
01744                      ext_mode, ron, gain, 1);
01745 
01746         cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
01747 
01748         if (images) {
01749         if (time_normalise)
01750             cpl_image_divide_scalar(images[0], alltime);
01751 
01752         if (!j) {
01753             if(dfs_save_image_null(frameset, parlist,
01754                        reduced_science_tag,
01755                        recipe, version)) {
01756             fors_pmos_extract_exit(NULL);
01757             }
01758         }
01759 
01760         if (dfs_save_image_ext(images[0], reduced_science_tag,
01761                        header)) {
01762             fors_pmos_extract_exit(NULL);
01763         }
01764 
01765         reduceds[j] = images[0];
01766 //      cpl_image_delete(images[0]);
01767     
01768         if (time_normalise)
01769             cpl_image_divide_scalar(images[1], alltime);
01770 
01771         if (!j) {
01772             if(dfs_save_image_null(frameset, parlist,
01773                        reduced_sky_tag,
01774                        recipe, version)) {
01775             fors_pmos_extract_exit(NULL);
01776             }
01777         }
01778 
01779         if (dfs_save_image_ext(images[1], reduced_sky_tag,
01780                        header)) {
01781             fors_pmos_extract_exit(NULL);
01782         }
01783         cpl_image_delete(images[1]);
01784     
01785         if (time_normalise)
01786             cpl_image_divide_scalar(images[2], alltime);
01787 
01788         if (!j) {
01789             if(dfs_save_image_null(frameset, parlist,
01790                        reduced_error_tag,
01791                        recipe, version)) {
01792             fors_pmos_extract_exit(NULL);
01793             }
01794         }
01795 
01796         if (dfs_save_image_ext(images[2], reduced_error_tag,
01797                        header)) {
01798             fors_pmos_extract_exit(NULL);
01799         }
01800 
01801         rerrors[j] = images[2];
01802 //      cpl_image_delete(images[2]);
01803 
01804         cpl_free(images);
01805         }
01806         else {
01807         cpl_msg_warning(recipe, "No objects found: the products "
01808                 "%s, %s, and %s are not created", 
01809                 reduced_science_tag, reduced_sky_tag, 
01810                 reduced_error_tag);
01811         }
01812 
01813     }
01814 
01815 //  slitss[j] = slits;
01816 //  cpl_table_delete(slits); slits = NULL;
01817 
01818 
01819 /*    if (skyglobal || skymedian >= 0) {   NSS */
01820     if (skyglobal || skymedian || skylocal) {
01821         if (time_normalise)
01822         cpl_image_divide_scalar(mappeds[j], alltime);
01823 
01824         if (!j) {
01825         if(dfs_save_image_null(frameset, parlist,
01826                        mapped_science_tag,
01827                        recipe, version)) {
01828             fors_pmos_extract_exit(NULL);
01829         }
01830         }
01831 
01832         if (dfs_save_image_ext(mappeds[j], mapped_science_tag,
01833                    header)) {
01834         fors_pmos_extract_exit(NULL);
01835         }
01836     }
01837 
01838     cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
01839     cpl_propertylist_delete(header); header = NULL;
01840 
01841     }
01842 
01843     cpl_table_delete(origslits);
01844 
01845     /* Stokes computation */
01846 
01847     nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
01848     nx       = cpl_image_get_size_x(reduceds[0]);
01849 
01850     header = cpl_propertylist_new();
01851     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01852     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01853     cpl_propertylist_update_double(header, "CRVAL1", 
01854                    startwavelength + dispersion/2);
01855     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01856     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01857        cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01858     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01859     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01860     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01861     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01862     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01863     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01864     
01865     if (circ) {
01866 
01867     cpl_image        *pv_im          = NULL;
01868     cpl_image        *pvnull_im      = NULL;
01869     cpl_image        *perr_im        = NULL;
01870 
01871     double           *p_v            = NULL;
01872     double           *p_vnull        = NULL;
01873     double           *perr           = NULL;
01874 
01875     double            mean_vnull;
01876 
01877     int p = -1;
01878     int total = 0;
01879 
01880     pv_im     = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01881     perr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01882 
01883     p_v     = cpl_image_get_data_double(pv_im);
01884     perr    = cpl_image_get_data_double(perr_im);
01885 
01886     if (nscience / 2 > 1) {
01887         pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01888         p_vnull = cpl_image_get_data_double(pvnull_im);
01889     }
01890 
01891     for (j = 0; j < nobjects; j++) {
01892         int k, m;
01893 
01894         double * ip_v,
01895            * ip_vnull, * iperr;
01896 
01897         float * data;
01898         float * iff,  * ierr;
01899 
01900         ip_v = p_v + (nobjects - 1 - j) * nx;
01901 
01902         if (nscience / 2 > 1)
01903         ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
01904 
01905         iperr = perr + (nobjects - 1 - j) * nx;
01906 
01907         while (total < j + 1) {
01908         p++;
01909         total += nobjs_per_slit[p];
01910         }
01911 
01912         for (k = 0; k < nscience / 2; k++) {
01913         float * if_o,  * if_e,  * ifdelta_o, * ifdelta_e;
01914 
01915         int pos   = fors_find_angle_pos(angles, nscience, 180 * k - 45);
01916         int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
01917 
01918         data = cpl_image_get_data_float(reduceds[pos]);
01919 
01920         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
01921                    + (total - j - 1)) * nx;
01922 
01923         if_e = data + (2 * (nobjects - total) 
01924                    + (total - j - 1)) * nx;
01925 
01926 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
01927 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
01928 
01929         data = cpl_image_get_data_float(reduceds[pos_d]);
01930 
01931         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
01932                    + (total - j - 1)) * nx;
01933 
01934         ifdelta_e = data + (2 * (nobjects - total) 
01935                    + (total - j - 1)) * nx;
01936 
01937 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
01938 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
01939 
01940         for (m = 0; m < nx; m++) {
01941 
01942             double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
01943             (if_o[m]      - if_e[m]     ) /
01944             (if_o[m]      + if_e[m]     ) -
01945             (ifdelta_o[m] - ifdelta_e[m]) /
01946             (ifdelta_o[m] + ifdelta_e[m]);
01947 
01948             quantity = isfinite(quantity) ? quantity : 0.0;
01949 
01950             /* PQ map computation */
01951             ip_v[m] += quantity * 0.5 / (nscience / 2);
01952 
01953             /* PQnull map computation */
01954             if (nscience / 2 > 1) {
01955             if (k % 2)
01956                 ip_vnull[m] += quantity * 0.5 / (nscience / 2);
01957             else
01958                 ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
01959             }
01960         }
01961         }
01962 
01963         /* Error map */
01964         data = cpl_image_get_data_float(reduceds[0]);
01965         iff  = data +  2 * (nobjects - 1 - j)      * nx;
01966 
01967         data = cpl_image_get_data_float(rerrors[0]);
01968         ierr = data +  2 * (nobjects - 1 - j)      * nx;
01969 
01970         for (m = 0; m < nx; m++)
01971         iperr[m] = iff[m] <= 0.0 ? 
01972             0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
01973 
01974         if (nscience / 2 > 1) {
01975         float * weights;
01976         float   max, sum, sum2, imean;
01977 
01978         int k;
01979 
01980         /* QC on U NULL */
01981         weights = cpl_malloc(sizeof(float) * nx);
01982 
01983         max = 0.0;
01984         for (k = 0; k < nx; k++) {
01985             if (max < iff[k]) max = iff[k];
01986         }
01987         
01988         for (k = 0; k < nx; k++) {
01989             weights[k] = iff[k] < 0.0 ? 
01990             0.0 : iff[k] * iff[k] / (max * max);
01991         }
01992         
01993         sum  = 0.0;
01994         sum2 = 0.0;
01995         for (k = 0; k < nx; k++) {
01996             sum  += weights[k] * ip_vnull[k];
01997             sum2 += weights[k];
01998         }
01999 
02000         cpl_free(weights);
02001 
02002         imean = sum / sum2;
02003 
02004         mean_vnull += (imean - mean_vnull) / (j + 1.0);
02005         }
02006     }
02007 
02008     if (dfs_save_image(frameset, pv_im, reduced_v_tag, header, 
02009                parlist, recipe, version))
02010         fors_pmos_extract_exit(NULL);
02011 
02012     if (nscience / 2 > 1) {
02013         char * pipefile, * keyname;
02014         cpl_propertylist * qheader = dfs_load_header(frameset, science_tag, 0);
02015 
02016             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02017             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02018             cpl_propertylist_update_double(qheader, "CRVAL1", 
02019                                startwavelength + dispersion/2);
02020             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02021             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02022                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02023             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02024             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02025             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02026             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02027             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02028             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02029 
02030         fors_qc_start_group(qheader, "2.0", instrume);
02031 
02032         /*
02033          * QC1 group header
02034          */
02035 
02036         if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag,
02037                      "Product category", instrume))
02038         fors_pmos_extract_exit("Cannot write product category to "
02039                      "QC log file");
02040 
02041         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02042                        "DPR type", instrume))
02043         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02044                      "lamp header");
02045 
02046         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02047                        "Template", instrume))
02048         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02049                      "lamp header");
02050 
02051         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02052                        "Grism name", instrume))
02053         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02054                      "lamp header");
02055 
02056         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02057                        "Grism identifier", instrume))
02058         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02059                      "lamp header");
02060 
02061         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02062         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02063                        "Filter name", instrume);
02064 
02065         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02066                        "Collimator name", instrume))
02067         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02068                      "lamp header");
02069 
02070         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02071                        "Chip identifier", instrume))
02072         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02073                      "lamp header");
02074 
02075         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02076                        "Archive name of input data", 
02077                        instrume))
02078         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02079                      "lamp header");
02080 
02081         pipefile = dfs_generate_filename(reduced_nul_v_tag);
02082         if (fors_qc_write_string("PIPEFILE", pipefile,
02083                      "Pipeline product name", instrume))
02084         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02085         cpl_free(pipefile); pipefile = NULL;
02086 
02087 
02088         /*
02089          * QC1 parameters
02090          */
02091 
02092         keyname = "QC.NULL.V.MEAN";
02093             
02094         if (fors_qc_write_qc_double(qheader, mean_vnull,
02095                     keyname, NULL,
02096                     "Mean V null parameter",
02097                     instrume)) {
02098         fors_pmos_extract_exit("Cannot write mean Q null parameter "
02099                      "to QC log file");
02100         }
02101 
02102         fors_qc_end_group();
02103 
02104         if (dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader, 
02105                    parlist, recipe, version))
02106         fors_pmos_extract_exit(NULL);
02107 
02108         cpl_propertylist_delete(qheader);
02109     }
02110 
02111     if (dfs_save_image(frameset, perr_im, reduced_error_v_tag, header, 
02112                parlist, recipe, version))
02113         fors_pmos_extract_exit(NULL);
02114 
02115     cpl_image_delete(pv_im);
02116     cpl_image_delete(pvnull_im);
02117     cpl_image_delete(perr_im);
02118     } else {
02119     cpl_image        *pq_im          = NULL;
02120     cpl_image        *pu_im          = NULL;
02121     cpl_image        *pl_im          = NULL;
02122 
02123     cpl_image        *pqnull_im      = NULL;
02124     cpl_image        *punull_im      = NULL;
02125 
02126     cpl_image        *pqerr_im        = NULL;
02127     cpl_image        *puerr_im        = NULL;
02128     cpl_image        *plerr_im        = NULL;
02129 
02130     cpl_image        *pang_im        = NULL;
02131     cpl_image        *pangerr_im        = NULL;
02132 
02133     double           *p_q            = NULL;
02134     double           *p_u            = NULL;
02135     double           *p_l            = NULL;
02136 
02137     double           *p_qnull        = NULL;
02138     double           *p_unull        = NULL;
02139 
02140     double           *pqerr           = NULL;
02141     double           *puerr           = NULL;
02142     double           *plerr           = NULL;
02143 
02144     double           *pang           = NULL;
02145     double           *pangerr           = NULL;
02146 
02147     int k, m;
02148 
02149     cpl_image * correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
02150     double    * correct    = cpl_image_get_data_double(correct_im);
02151 
02152     double mean_unull, mean_qnull;
02153 
02154     int p = -1;
02155     int total = 0;
02156 
02157     pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02158     pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02159     pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02160 
02161     pqerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02162     puerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02163     plerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02164 
02165     pang_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02166     pangerr_im   = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02167 
02168     p_q = cpl_image_get_data_double(pq_im);
02169     p_u = cpl_image_get_data_double(pu_im);
02170     p_l = cpl_image_get_data_double(pl_im);
02171 
02172     if (nscience / 4 > 1) {
02173         pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02174         punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02175 
02176         p_qnull = cpl_image_get_data_double(pqnull_im);
02177         p_unull = cpl_image_get_data_double(punull_im);
02178     } else {
02179         cpl_msg_warning(cpl_func, 
02180                 "Not enough pairs to compute null parameters");
02181     }
02182 
02183     pqerr = cpl_image_get_data_double(pqerr_im);
02184     puerr = cpl_image_get_data_double(puerr_im);
02185     plerr = cpl_image_get_data_double(plerr_im);
02186 
02187     pang = cpl_image_get_data_double(pang_im);
02188     pangerr = cpl_image_get_data_double(pangerr_im);
02189 
02190     if (chromatism) {
02191         cpl_table * chrotbl = 
02192         dfs_load_table(frameset, chrom_table_tag, 1);
02193 
02194         int      nrow   = cpl_table_get_nrow(chrotbl);
02195         float  * lambda = cpl_table_get_data_float(chrotbl, "lambda");
02196         float  * theta  = cpl_table_get_data_float(chrotbl, "eps_theta");
02197 
02198         for (j = 0; j < nx; j++) {
02199         double c_wave = 
02200             startwavelength + dispersion / 2 + j * dispersion;
02201         
02202         int found = 0;
02203 
02204         for (k = 0; k < nrow - 1; k++) {
02205             if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
02206             found = 1;
02207             break;
02208             }
02209         }
02210 
02211         if (found) {
02212             correct[j] = (theta [k + 1] - theta [k]) /
02213                      (lambda[k + 1] - lambda[k]) *
02214                      (c_wave        - lambda[k])   + theta[k];
02215                     correct[j] *= M_PI / 180;   /* Radians */
02216         }
02217                 else if (j)
02218                     correct[j] = correct[j-1];
02219                 else
02220                     correct[j] = 0.0;
02221 
02222         }
02223 
02224         cpl_table_delete(chrotbl);
02225     }
02226 
02227     for (j = 0; j < nobjects; j++) {
02228         double * ip_q,     * ip_u, * ip_l, 
02229         * ip_qnull, * ip_unull, * ipqerr, * ipuerr, * iplerr,
02230         * ipang, * ipangerr;
02231 
02232         float * data;
02233         float * iffq,  * ierrq, * iffu, * ierru;
02234 
02235         int pos, pos_d;
02236 
02237         ip_q = p_q + (nobjects - 1 - j) * nx;
02238         ip_u = p_u + (nobjects - 1 - j) * nx;
02239         ip_l = p_l + (nobjects - 1 - j) * nx;
02240 
02241         if (nscience / 4 > 1) {
02242         ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
02243         ip_unull = p_unull + (nobjects - 1 - j) * nx;
02244         }
02245 
02246         ipqerr = pqerr + (nobjects - 1 - j) * nx;
02247         ipuerr = puerr + (nobjects - 1 - j) * nx;
02248         iplerr = plerr + (nobjects - 1 - j) * nx;
02249 
02250         ipang = pang + (nobjects - 1 - j) * nx;
02251         ipangerr = pangerr + (nobjects - 1 - j) * nx;
02252 
02253         while (total < j + 1) {
02254         p++;
02255         total += nobjs_per_slit[p];
02256         }
02257 
02258         for (k = 0; k < nscience / 4; k++) {
02259         float * if_o,  * if_e,  * ifdelta_o, * ifdelta_e;
02260 
02261         /* First P_Q */
02262 
02263         pos   = fors_find_angle_pos(angles, nscience, 90 * k);
02264         pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
02265 
02266         data = cpl_image_get_data_float(reduceds[pos]);
02267 
02268         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02269                    + (total - j - 1)) * nx;
02270 
02271         if_e = data + (2 * (nobjects - total) 
02272                    + (total - j - 1)) * nx;
02273 
02274 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02275 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
02276 
02277         data = cpl_image_get_data_float(reduceds[pos_d]);
02278 
02279         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02280                    + (total - j - 1)) * nx;
02281 
02282         ifdelta_e = data + (2 * (nobjects - total) 
02283                    + (total - j - 1)) * nx;
02284 
02285 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02286 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
02287 
02288         for (m = 0; m < nx; m++) {
02289 
02290             double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02291             (if_o[m]      - if_e[m]     ) /
02292             (if_o[m]      + if_e[m]     ) -
02293             (ifdelta_o[m] - ifdelta_e[m]) /
02294             (ifdelta_o[m] + ifdelta_e[m]);
02295 
02296             quantity = isfinite(quantity) ? quantity : 0.0;
02297 
02298             /* PQ map computation */
02299             ip_q[m] += quantity * 0.5 / (nscience / 4);
02300 
02301             /* PQnull map computation */
02302             if (nscience / 4 > 1) {
02303             if (k % 2)
02304                 ip_qnull[m] += quantity * 0.5 / (nscience / 4);
02305             else
02306                 ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
02307             }
02308         }
02309 
02310         /* Now P_U */
02311 
02312         pos   = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
02313         pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
02314 
02315         data = cpl_image_get_data_float(reduceds[pos]);
02316 
02317         if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02318                    + (total - j - 1)) * nx;
02319 
02320         if_e = data + (2 * (nobjects - total) 
02321                    + (total - j - 1)) * nx;
02322 
02323 //      if_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02324 //      if_e = data +  2 * (nobjects - 1 - j)      * nx;
02325 
02326         data = cpl_image_get_data_float(reduceds[pos_d]);
02327 
02328         ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 
02329                    + (total - j - 1)) * nx;
02330 
02331         ifdelta_e = data + (2 * (nobjects - total) 
02332                    + (total - j - 1)) * nx;
02333 
02334 //      ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx;
02335 //      ifdelta_e = data +  2 * (nobjects - 1 - j)      * nx;
02336 
02337         for (m = 0; m < nx; m++) {
02338 
02339             double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02340             (if_o[m]      - if_e[m]     ) /
02341             (if_o[m]      + if_e[m]     ) -
02342             (ifdelta_o[m] - ifdelta_e[m]) /
02343             (ifdelta_o[m] + ifdelta_e[m]);
02344 
02345             quantity = isfinite(quantity) ? quantity : 0.0;
02346 
02347             /* PU map computation */
02348             ip_u[m] += quantity * 0.5 / (nscience / 4);
02349 
02350             /* PUnull map computation */
02351             if (nscience / 4 > 1) {
02352             if (k % 2)
02353                 ip_unull[m] += quantity * 0.5 / (nscience / 4);
02354             else
02355                 ip_unull[m] -= quantity * 0.5 / (nscience / 4);
02356             }
02357         }
02358         }
02359 
02360         /* Error map */
02361 
02362         pos   = fors_find_angle_pos(angles, nscience, 0.0);
02363 
02364         data = cpl_image_get_data_float(reduceds[pos]);
02365         iffq  = data +  2 * (nobjects - 1 - j)      * nx;
02366 
02367         data = cpl_image_get_data_float(rerrors[pos]);
02368         ierrq = data +  2 * (nobjects - 1 - j)      * nx;
02369         
02370         pos   = fors_find_angle_pos(angles, nscience, 22.5);
02371 
02372         data = cpl_image_get_data_float(reduceds[pos]);
02373         iffu  = data +  2 * (nobjects - 1 - j)      * nx;
02374 
02375         data = cpl_image_get_data_float(rerrors[pos]);
02376         ierru = data +  2 * (nobjects - 1 - j)      * nx;
02377 
02378         for (m = 0; m < nx; m++) {
02379 
02380         double radicand; 
02381 
02382         ipqerr[m] = iffq[m] <= 0.0 ? 
02383             0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
02384 
02385         ipuerr[m] = iffu[m] <= 0.0 ? 
02386             0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
02387 
02388         iplerr[m] = CPL_MATH_SQRT1_2 * 0.5 * (ipqerr[m] + ipuerr[m]);
02389 
02390 /* Added: */
02391         if (chromatism) {
02392             ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 
02393                               ip_u[m] * sin(2 * correct[m]);
02394 
02395             ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 
02396                               ip_u[m] * cos(2 * correct[m]);
02397         }
02398 /* End added */
02399 
02400         /* PL computation */
02401         ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
02402 
02403         /* P angle computation */
02404         ipang[m] = (ip_q[m] == 0.0 ?
02405             (ip_u[m] > 0.0 ? 45.0 : 135.0)
02406             : 0.5 * (atan2(ip_u[m], ip_q[m]) * 180 / M_PI + 
02407                  ((atan2(ip_u[m], ip_q[m]) > 0.0 ? 0.0 : 360.0))));
02408 
02409         /* Error on the angle computation */
02410         radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] + 
02411                    ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
02412   
02413         ipangerr[m] = ip_l[m] == 0.0 ? 0.0 :
02414              sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI;
02415 
02416                 /* 
02417                  * Note: no need to apply chromatism correction to angle,
02418                  * it is implicit in Q and U correction applied before.
02419                  */
02420 
02421 /* Removed: 
02422         if (chromatism) {
02423             ipang[m] -= correct[m];
02424         
02425             ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 
02426                               ip_u[m] * sin(2 * correct[m]);
02427 
02428             ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 
02429                               ip_u[m] * cos(2 * correct[m]);
02430         
02431         }
02432   end removed */
02433         }
02434 
02435         if (nscience / 4 > 1) {
02436         float * weights;
02437         float   max, sum, sum2, imean;
02438 
02439         int k;
02440 
02441         /* QC on U NULL */
02442         weights = cpl_malloc(sizeof(float) * nx);
02443 
02444         max = 0.0;
02445         for (k = 0; k < nx; k++) {
02446             if (max < iffq[k]) max = iffq[k];
02447         }
02448         
02449         for (k = 0; k < nx; k++) {
02450             weights[k] = iffq[k] < 0.0 ? 
02451             0.0 : iffq[k] * iffq[k] / (max * max);
02452         }
02453         
02454         sum  = 0.0;
02455         sum2 = 0.0;
02456         for (k = 0; k < nx; k++) {
02457             sum  += weights[k] * ip_qnull[k];
02458             sum2 += weights[k];
02459         }
02460 
02461         cpl_free(weights);
02462 
02463         imean = sum / sum2;
02464 
02465         mean_qnull += (imean - mean_qnull) / (j + 1.0);
02466           
02467         /* QC on U NULL */
02468         weights = cpl_malloc(sizeof(float) * nx);
02469         
02470         max = 0.0;
02471         for (k = 0; k < nx; k++) {
02472             if (max < iffu[k]) max = iffu[k];
02473         }
02474         
02475         for (k = 0; k < nx; k++) {
02476             weights[k] = iffu[k] < 0.0 ? 
02477             0.0 : iffu[k] * iffu[k] / (max * max);
02478         }
02479         
02480         sum  = 0.0;
02481         sum2 = 0.0;
02482         for (k = 0; k < nx; k++) {
02483             sum  += weights[k] * ip_unull[k];
02484             sum2 += weights[k];
02485         }
02486 
02487         cpl_free(weights);
02488 
02489         imean = sum / sum2;
02490 
02491         mean_unull += (imean - mean_unull) / (j + 1.0);
02492         }
02493     }
02494 
02495     cpl_image_delete(correct_im);
02496 
02497     if (dfs_save_image(frameset, pq_im, reduced_q_tag, header, 
02498                parlist, recipe, version))
02499         fors_pmos_extract_exit(NULL);
02500 
02501     if (dfs_save_image(frameset, pu_im, reduced_u_tag, header, 
02502                parlist, recipe, version))
02503         fors_pmos_extract_exit(NULL);
02504 
02505     if (dfs_save_image(frameset, pl_im, reduced_l_tag, header, 
02506                parlist, recipe, version))
02507         fors_pmos_extract_exit(NULL);
02508 
02509     if (nscience / 4 > 1) {
02510         char *pipefile; 
02511             char *keyname;
02512         cpl_propertylist *qheader = dfs_load_header(frameset, 
02513                                                         science_tag, 0);
02514 
02515             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02516             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02517             cpl_propertylist_update_double(qheader, "CRVAL1", 
02518                                startwavelength + dispersion/2);
02519             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02520             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02521                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02522             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02523             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02524             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02525             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02526             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02527             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02528 
02529         fors_qc_start_group(qheader, "2.0", instrume);
02530 
02531         /*
02532          * QC1 group header
02533          */
02534 
02535         if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag,
02536                      "Product category", instrume))
02537         fors_pmos_extract_exit("Cannot write product category to "
02538                      "QC log file");
02539 
02540         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02541                        "DPR type", instrume))
02542         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02543                      "lamp header");
02544 
02545         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02546                        "Template", instrume))
02547         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02548                      "lamp header");
02549 
02550         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02551                        "Grism name", instrume))
02552         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02553                      "lamp header");
02554 
02555         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02556                        "Grism identifier", instrume))
02557         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02558                      "lamp header");
02559 
02560         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02561         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02562                        "Filter name", instrume);
02563 
02564         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02565                        "Collimator name", instrume))
02566         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02567                      "lamp header");
02568 
02569         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02570                        "Chip identifier", instrume))
02571         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02572                      "lamp header");
02573 
02574         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02575                        "Archive name of input data", 
02576                        instrume))
02577         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02578                      "lamp header");
02579 
02580         pipefile = dfs_generate_filename(reduced_nul_q_tag);
02581         if (fors_qc_write_string("PIPEFILE", pipefile,
02582                      "Pipeline product name", instrume))
02583         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02584         cpl_free(pipefile); pipefile = NULL;
02585 
02586 
02587         /*
02588          * QC1 parameters
02589          */
02590 
02591         keyname = "QC.NULL.Q.MEAN";
02592             
02593         if (fors_qc_write_qc_double(qheader, mean_qnull,
02594                     keyname, NULL,
02595                     "Mean Q null parameter",
02596                     instrume)) {
02597         fors_pmos_extract_exit("Cannot write mean Q null parameter "
02598                      "to QC log file");
02599         }
02600 
02601         fors_qc_end_group();
02602 
02603         if (dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader, 
02604                    parlist, recipe, version))
02605         fors_pmos_extract_exit(NULL);
02606 
02607         cpl_propertylist_delete(qheader);
02608 
02609         qheader = dfs_load_header(frameset, science_tag, 0);
02610 
02611             cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02612             cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02613             cpl_propertylist_update_double(qheader, "CRVAL1", 
02614                                startwavelength + dispersion/2);
02615             cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02616             /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
02617                cpl_propertylist_update_double(header, "CDELT2", 1.0); */
02618             cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02619             cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02620             cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02621             cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02622             cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02623             cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02624 
02625         fors_qc_start_group(qheader, "2.0", instrume);
02626 
02627         /*
02628          * QC1 group header
02629          */
02630 
02631         if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag,
02632                      "Product category", instrume))
02633         fors_pmos_extract_exit("Cannot write product category to "
02634                      "QC log file");
02635 
02636         if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02637                        "DPR type", instrume))
02638         fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02639                      "lamp header");
02640 
02641         if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02642                        "Template", instrume))
02643         fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02644                      "lamp header");
02645 
02646         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02647                        "Grism name", instrume))
02648         fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02649                      "lamp header");
02650 
02651         if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02652                        "Grism identifier", instrume))
02653         fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02654                      "lamp header");
02655 
02656         if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02657         fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02658                        "Filter name", instrume);
02659 
02660         if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02661                        "Collimator name", instrume))
02662         fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02663                      "lamp header");
02664 
02665         if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02666                        "Chip identifier", instrume))
02667         fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02668                      "lamp header");
02669 
02670         if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02671                        "Archive name of input data", 
02672                        instrume))
02673         fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02674                      "lamp header");
02675 
02676         pipefile = dfs_generate_filename(reduced_nul_u_tag);
02677         if (fors_qc_write_string("PIPEFILE", pipefile,
02678                      "Pipeline product name", instrume))
02679         fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02680         cpl_free(pipefile); pipefile = NULL;
02681 
02682 
02683         /*
02684          * QC1 parameters
02685          */
02686 
02687         keyname = "QC.NULL.U.MEAN";
02688             
02689         if (fors_qc_write_qc_double(qheader, mean_unull,
02690                     keyname, NULL,
02691                     "Mean U null parameter",
02692                     instrume)) {
02693         fors_pmos_extract_exit("Cannot write mean U null parameter "
02694                      "to QC log file");
02695         }
02696 
02697         fors_qc_end_group();
02698 
02699         if (dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader, 
02700                    parlist, recipe, version))
02701         fors_pmos_extract_exit(NULL);
02702 
02703         cpl_propertylist_delete(qheader);
02704     }
02705 
02706     if (dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header, 
02707                parlist, recipe, version))
02708         fors_pmos_extract_exit(NULL);
02709 
02710     if (dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header, 
02711                parlist, recipe, version))
02712         fors_pmos_extract_exit(NULL);
02713 
02714     if (dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header, 
02715                parlist, recipe, version))
02716         fors_pmos_extract_exit(NULL);
02717 
02718     if (dfs_save_image(frameset, pang_im, reduced_angle_tag, header, 
02719                parlist, recipe, version))
02720         fors_pmos_extract_exit(NULL);
02721 
02722     if (dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag, 
02723                header, parlist, recipe, version))
02724         fors_pmos_extract_exit(NULL);
02725 
02726     cpl_image_delete(pq_im);
02727     cpl_image_delete(pu_im);
02728     cpl_image_delete(pl_im);
02729 
02730     cpl_image_delete(pqnull_im);
02731     cpl_image_delete(punull_im);
02732 
02733     cpl_image_delete(pqerr_im);
02734     cpl_image_delete(puerr_im);
02735     cpl_image_delete(plerr_im);
02736     cpl_image_delete(pang_im);
02737     cpl_image_delete(pangerr_im);
02738     }
02739 
02740     cpl_propertylist_delete(header);
02741 
02742     /* End of Stokes computation */
02743 
02744     for (j = 0; j < nscience; j++) {
02745     cpl_image_delete(reduceds[j]);
02746     cpl_image_delete(rerrors[j]);
02747     cpl_table_delete(slitss[j]);
02748     cpl_image_delete(mappeds[j]);
02749     }
02750 
02751     cpl_free(reduceds);
02752     cpl_free(rerrors);
02753     cpl_free(slitss);
02754     cpl_free(mappeds);
02755 
02756     cpl_free(instrume); instrume = NULL;
02757 
02758     cpl_free(skylocalmaps);
02759     cpl_free(nobjs_per_slit);
02760 
02761     if (cpl_error_get_code()) {
02762         cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
02763         fors_pmos_extract_exit(NULL);
02764     }
02765     else 
02766         return 0;
02767 }
02768 
02769 /*----------------------------------------------------------------------------*/
02780 /*----------------------------------------------------------------------------*/
02781 static float * fors_check_angles(cpl_frameset * frameset,
02782                  int pmos, const char *tag, int * circ)
02783 {
02784     float     *angles  = NULL;
02785     cpl_frame *c_frame = NULL;
02786     char      *ret_id  = NULL;
02787 
02788     int i = 0;
02789 
02790     angles = cpl_malloc(sizeof(float) * pmos);
02791 
02792     for (c_frame  = cpl_frameset_find(frameset, tag);
02793      c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
02794 
02795         cpl_propertylist * header =
02796         cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
02797     
02798     if (!ret_id) {
02799         ret_id = cpl_strdup(cpl_propertylist_get_string(header, 
02800                                                         "ESO INS OPTI4 ID"));
02801 
02802         if (ret_id[1] != '5' && ret_id[1] != '4') {
02803         cpl_msg_error(cpl_func, 
02804                   "Unknown retarder plate id: %s", ret_id);
02805         return NULL;
02806         }
02807     } else {
02808         char * c_ret_id = (char *)
02809         cpl_propertylist_get_string(header, "ESO INS OPTI4 ID");
02810         if (ret_id[1] != c_ret_id[1]) {
02811         cpl_msg_error(cpl_func, "Input frames are not from the same "
02812                   "retarder plate");
02813         return NULL;
02814         }
02815     }
02816     
02817     if (ret_id[1] == '5') {  /* Linear polarimetry */
02818         angles[i] = (float)
02819         cpl_propertylist_get_double(header, "ESO INS RETA2 ROT");
02820         *circ = 0;
02821     } else {                 /* Circular polarimetry */
02822         angles[i] = (float)
02823         cpl_propertylist_get_double(header, "ESO INS RETA4 ROT");
02824         *circ = 1;
02825     }
02826 
02827         cpl_propertylist_delete(header);
02828     i++;
02829     }
02830 
02831     cpl_free(ret_id);
02832 
02833     if (*circ) {
02834     if (pmos != 2 && pmos != 4) {
02835         cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02836                           "found, but either 2 or 4 are required for "
02837                           "circular polarization measurements!", pmos);
02838         return NULL;
02839     }
02840     } else {
02841     if (pmos != 4 && pmos != 8 && pmos != 16) {
02842         cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02843                           "found, but either 4, 8, or 16 are required for "
02844                           "linear polarization measurements!", pmos);
02845         return NULL;
02846     }
02847     }
02848     
02849     /* Check completeness */
02850 
02851     if (*circ) {
02852         for (i = 0; i < pmos; i++) {
02853             if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
02854                 const char *cangles;
02855                 switch (pmos) {
02856                 case 2: cangles  = "-45.0, 45.0"; break;
02857                 case 4: cangles  = "-45.0, 45.0, 135.0, 225.0"; break;
02858                 default: assert(0);
02859                 }  
02860 
02861             cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02862                               "angle %.2f. All angles %s must be provided.",
02863                               angles[i], cangles);
02864                 return NULL;
02865             }
02866         }
02867     }
02868     else {
02869         for (i = 0; i < pmos; i++) {
02870             if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
02871                 const char *cangles;
02872                 switch (pmos) {
02873                 case 4: cangles  = "0.0, 22.5, 45.0, 67.5"; break;
02874                 case 8: cangles  = "0.0, 22.5, 45.0, 67.5, "
02875                                    "90.0, 112.5, 135.0, 157.5"; break;
02876                 case 16: cangles = "0.0, 22.5, 45.0, 67.5, "
02877                                    "90.0, 112.5, 135.0, 157.5, "
02878                                    "180.0, 202.5, 225.0, 247.5, "
02879                                    "270.0, 292.5, 315.0, 337.5"; break;
02880                 default: assert(0);
02881                 }  
02882 
02883             cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02884                               "angle %.2f. All angles %s must be provided.",
02885                               angles[i], cangles);
02886                 return NULL;
02887             }
02888         }
02889     }
02890 
02891     return angles;
02892 }
02893 
02894 /*----------------------------------------------------------------------------*/
02902 /*----------------------------------------------------------------------------*/
02903 static int
02904 fors_find_angle_pos(float * angles, int nangles, float angle)
02905 {
02906     int i, match = 0;
02907 
02908     for (i = 0; i < nangles; i++) {
02909     if (fabs(angles[i]         - angle) < 1.0 || 
02910         fabs(angles[i] - 360.0 - angle) < 1.0) {
02911         match = 1;
02912         break;
02913     }
02914     }
02915 
02916     return match ? i : -1;
02917 }

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