recipes/fors_extract.c

00001 /* $Id: fors_extract.c,v 1.9 2010/09/14 07:38:16 cizzo Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cizzo $
00023  * $Date: 2010/09/14 07:38:16 $
00024  * $Revision: 1.9 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <string.h>
00033 #include <math.h>
00034 #include <cpl.h>
00035 #include <moses.h>
00036 #include <fors_dfs.h>
00037 
00038 static int fors_extract_create(cpl_plugin *);
00039 static int fors_extract_exec(cpl_plugin *);
00040 static int fors_extract_destroy(cpl_plugin *);
00041 static int fors_extract(cpl_parameterlist *, cpl_frameset *);
00042 
00043 static char fors_extract_description[] =
00044 "This recipe is used to reduce scientific spectra using the global\n"
00045 "distortion table created by the recipe fors_calib. The spectra are\n"
00046 "bias subtracted, flat fielded (if a normalised flat field is specified)\n"
00047 "and remapped eliminating the optical distortions. The wavelength calibration\n"
00048 "can be optionally upgraded using a number of sky lines: if no sky lines\n"
00049 "catalog of wavelengths is specified, an internal one is used instead.\n"
00050 "If the alignment to the sky lines is performed, the applied dispersion\n"
00051 "coefficient table is upgraded and saved to disk, and a new CCD wavelengths\n"
00052 "map is created.\n"
00053 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n"
00054 "depending on the instrument mode, and in particular on the grism used)\n"
00055 "may also be specified: this table contains a default recipe parameter\n" 
00056 "setting to control the way spectra are extracted for a specific instrument\n"
00057 "mode, as it is used for automatic run of the pipeline on Paranal and in\n" 
00058 "Garching. If this table is specified, it will modify the default recipe\n" 
00059 "parameter setting, with the exception of those parameters which have been\n" 
00060 "explicitly modifyed on the command line. If a grism table is not specified,\n"
00061 "the input recipe parameters values will always be read from the command\n" 
00062 "line, or from an esorex configuration file if present, or from their\n" 
00063 "generic default values (that are rarely meaningful).\n" 
00064 "In the table below the MXU acronym can be read alternatively as MOS\n"
00065 "and LSS, depending on the instrument mode of the input data. Either a\n"
00066 "scientific or a standard star exposure can be specified in input (not\n"
00067 "both).\n\n"
00068 "Input files:\n\n"
00069 "  DO category:               Type:       Explanation:         Required:\n"
00070 "  SCIENCE_MXU                Raw         Scientific exposure     Y\n"
00071 "  or STANDARD_MXU            Raw         Standard star exposure  Y\n"
00072 "  MASTER_BIAS                Calib       Master bias             Y\n"
00073 "  GRISM_TABLE                Calib       Grism table             .\n"
00074 "  MASTER_SKYLINECAT          Calib       Sky lines catalog       .\n"
00075 "\n"
00076 "  MASTER_NORM_FLAT_MXU       Calib       Normalised flat field   .\n"
00077 "  MASTER_DISTORTION_TABLE    Calib       Global distortion model .\n"
00078 "\n"
00079 "  or, in case of LSS-like MOS/MXU data,\n"
00080 "\n"
00081 "  MASTER_NORM_FLAT_LONG_MXU  Calib       Normalised flat field   .\n"
00082 "Output files:\n\n"
00083 "  DO category:               Data type:  Explanation:\n"
00084 "  REDUCED_SCI_MXU            FITS image  Extracted scientific spectra\n"
00085 "  REDUCED_SKY_SCI_MXU        FITS image  Extracted sky spectra\n"
00086 "  REDUCED_ERROR_SCI_MXU      FITS image  Errors on extracted spectra\n"
00087 "  UNMAPPED_SCI_MXU           FITS image  Sky subtracted scientific spectra\n"
00088 "  MAPPED_SCI_MXU             FITS image  Rectified scientific spectra\n"
00089 "  MAPPED_ALL_SCI_MXU         FITS image  Rectified science spectra with sky\n"
00090 "  MAPPED_SKY_SCI_MXU         FITS image  Rectified sky spectra\n"
00091 "  UNMAPPED_SKY_SCI_MXU           FITS image  Sky on CCD\n"
00092 "  GLOBAL_SKY_SPECTRUM_MXU    FITS table  Global sky spectrum\n"
00093 "  OBJECT_TABLE_SCI_MXU       FITS table  Positions of detected objects\n"
00094 "\n"
00095 "  Only if the sky-alignment of the wavelength solution is requested:\n"
00096 "  SKY_SHIFTS_LONG_SCI_MXU    FITS table  Sky lines offsets (LSS-like data)\n"
00097 "  or SKY_SHIFTS_SLIT_SCI_MXU FITS table  Sky lines offsets (MOS-like data)\n"
00098 "  DISP_COEFF_SCI_MXU         FITS table  Upgraded dispersion coefficients\n"
00099 "  WAVELENGTH_MAP_SCI_MXU     FITS image  Upgraded wavelength map\n\n";
00100 
00101 #define fors_extract_exit(message)            \
00102 {                                             \
00103 if (message) cpl_msg_error(recipe, message);  \
00104 cpl_free(exptime);                            \
00105 cpl_free(instrume);                           \
00106 cpl_image_delete(dummy);                      \
00107 cpl_image_delete(mapped);                     \
00108 cpl_image_delete(mapped_sky);                 \
00109 cpl_image_delete(mapped_cleaned);             \
00110 cpl_image_delete(skylocalmap);                \
00111 cpl_image_delete(skymap);                     \
00112 cpl_image_delete(smapped);                    \
00113 cpl_table_delete(offsets);                    \
00114 cpl_table_delete(global);                     \
00115 cpl_table_delete(sky);                        \
00116 cpl_image_delete(bias);                       \
00117 cpl_image_delete(spectra);                    \
00118 cpl_image_delete(coordinate);                 \
00119 cpl_image_delete(norm_flat);                  \
00120 cpl_image_delete(rainbow);                    \
00121 cpl_image_delete(rectified);                  \
00122 cpl_image_delete(wavemap);                    \
00123 cpl_propertylist_delete(header);              \
00124 cpl_propertylist_delete(save_header);         \
00125 cpl_table_delete(grism_table);                \
00126 cpl_table_delete(idscoeff);                   \
00127 cpl_table_delete(maskslits);                  \
00128 cpl_table_delete(overscans);                  \
00129 cpl_table_delete(polytraces);                 \
00130 cpl_table_delete(slits);                      \
00131 cpl_table_delete(wavelengths);                \
00132 cpl_vector_delete(lines);                     \
00133 cpl_msg_indent_less();                        \
00134 return -1;                                    \
00135 }
00136 
00137 
00138 #define fors_extract_exit_memcheck(message)            \
00139 {                                                      \
00140 if (message) cpl_msg_info(recipe, message);            \
00141 printf("free exptime (%p)\n", exptime);                \
00142 cpl_free(exptime);                                     \
00143 printf("free instrume (%p)\n", instrume);              \
00144 cpl_free(instrume);                                    \
00145 printf("free dummy (%p)\n", dummy);                    \
00146 cpl_image_delete(dummy);                               \
00147 printf("free mapped (%p)\n", mapped);                  \
00148 cpl_image_delete(mapped);                              \
00149 printf("free mapped_cleaned (%p)\n", mapped_cleaned);  \
00150 cpl_image_delete(mapped_cleaned);                      \
00151 printf("free mapped_sky (%p)\n", mapped_sky);          \
00152 cpl_image_delete(mapped_sky);                          \
00153 printf("free skylocalmap (%p)\n", skylocalmap);        \
00154 cpl_image_delete(skylocalmap);                         \
00155 printf("free skymap (%p)\n", skymap);                  \
00156 cpl_image_delete(skymap);                              \
00157 printf("free smapped (%p)\n", smapped);                \
00158 cpl_image_delete(smapped);                             \
00159 printf("free offsets (%p)\n", offsets);                \
00160 cpl_table_delete(offsets);                             \
00161 printf("free global (%p)\n", global);                  \
00162 cpl_table_delete(global);                              \
00163 printf("free sky (%p)\n", sky);                        \
00164 cpl_table_delete(sky);                                 \
00165 printf("free bias (%p)\n", bias);                      \
00166 cpl_image_delete(bias);                                \
00167 printf("free spectra (%p)\n", spectra);                \
00168 cpl_image_delete(spectra);                             \
00169 printf("free coordinate (%p)\n", coordinate);          \
00170 cpl_image_delete(coordinate);                          \
00171 printf("free norm_flat (%p)\n", norm_flat);            \
00172 cpl_image_delete(norm_flat);                           \
00173 printf("free rainbow (%p)\n", rainbow);                \
00174 cpl_image_delete(rainbow);                             \
00175 printf("free rectified (%p)\n", rectified);            \
00176 cpl_image_delete(rectified);                           \
00177 printf("free wavemap (%p)\n", wavemap);                \
00178 cpl_image_delete(wavemap);                             \
00179 printf("free header (%p)\n", header);                  \
00180 cpl_propertylist_delete(header);                       \
00181 printf("free save_header (%p)\n", save_header);        \
00182 cpl_propertylist_delete(save_header);                  \
00183 printf("free grism_table (%p)\n", grism_table);        \
00184 cpl_table_delete(grism_table);                         \
00185 printf("free idscoeff (%p)\n", idscoeff);              \
00186 cpl_table_delete(idscoeff);                            \
00187 printf("free maskslits (%p)\n", maskslits);            \
00188 cpl_table_delete(maskslits);                           \
00189 printf("free overscans (%p)\n", overscans);            \
00190 cpl_table_delete(overscans);                           \
00191 printf("free polytraces (%p)\n", polytraces);          \
00192 cpl_table_delete(polytraces);                          \
00193 printf("free slits (%p)\n", slits);                    \
00194 cpl_table_delete(slits);                               \
00195 printf("free wavelengths (%p)\n", wavelengths);        \
00196 cpl_table_delete(wavelengths);                         \
00197 printf("free lines (%p)\n", lines);                    \
00198 cpl_vector_delete(lines);                              \
00199 cpl_msg_indent_less();                                 \
00200 return 0;                                              \
00201 }
00202 
00203 
00215 int cpl_plugin_get_info(cpl_pluginlist *list)
00216 {
00217     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00218     cpl_plugin *plugin = &recipe->interface;
00219 
00220     cpl_plugin_init(plugin,
00221                     CPL_PLUGIN_API,
00222                     FORS_BINARY_VERSION,
00223                     CPL_PLUGIN_TYPE_RECIPE,
00224                     "fors_extract",
00225                     "Extraction of scientific spectra",
00226                     fors_extract_description,
00227                     "Carlo Izzo",
00228                     PACKAGE_BUGREPORT,
00229     "This file is currently part of the FORS Instrument Pipeline\n"
00230     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00231     "This program is free software; you can redistribute it and/or modify\n"
00232     "it under the terms of the GNU General Public License as published by\n"
00233     "the Free Software Foundation; either version 2 of the License, or\n"
00234     "(at your option) any later version.\n\n"
00235     "This program is distributed in the hope that it will be useful,\n"
00236     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00237     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00238     "GNU General Public License for more details.\n\n"
00239     "You should have received a copy of the GNU General Public License\n"
00240     "along with this program; if not, write to the Free Software Foundation,\n"
00241     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00242                     fors_extract_create,
00243                     fors_extract_exec,
00244                     fors_extract_destroy);
00245 
00246     cpl_pluginlist_append(list, plugin);
00247     
00248     return 0;
00249 }
00250 
00251 
00262 static int fors_extract_create(cpl_plugin *plugin)
00263 {
00264     cpl_recipe    *recipe;
00265     cpl_parameter *p;
00266 
00267 
00268     /* 
00269      * Check that the plugin is part of a valid recipe 
00270      */
00271 
00272     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00273         recipe = (cpl_recipe *)plugin;
00274     else 
00275         return -1;
00276 
00277     /* 
00278      * Create the parameters list in the cpl_recipe object 
00279      */
00280 
00281     recipe->parameters = cpl_parameterlist_new(); 
00282 
00283 
00284     /*
00285      * Dispersion
00286      */
00287 
00288     p = cpl_parameter_new_value("fors.fors_extract.dispersion",
00289                                 CPL_TYPE_DOUBLE,
00290                                 "Resampling step (Angstrom/pixel)",
00291                                 "fors.fors_extract",
00292                                 0.0);
00293     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00294     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00295     cpl_parameterlist_append(recipe->parameters, p);
00296 
00297     /*
00298      * Sky lines alignment
00299      */
00300 
00301     p = cpl_parameter_new_value("fors.fors_extract.skyalign",
00302                                 CPL_TYPE_INT,
00303                                 "Polynomial order for sky lines alignment, "
00304                                 "or -1 to avoid alignment",
00305                                 "fors.fors_extract",
00306                                 0);
00307     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
00308     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00309     cpl_parameterlist_append(recipe->parameters, p);
00310 
00311     /*
00312      * Line catalog table column containing the sky reference wavelengths
00313      */
00314 
00315     p = cpl_parameter_new_value("fors.fors_extract.wcolumn",
00316                                 CPL_TYPE_STRING,
00317                                 "Name of sky line catalog table column "
00318                                 "with wavelengths",
00319                                 "fors.fors_extract",
00320                                 "WLEN");
00321     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00322     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00323     cpl_parameterlist_append(recipe->parameters, p);
00324 
00325     /*
00326      * Start wavelength for spectral extraction
00327      */
00328 
00329     p = cpl_parameter_new_value("fors.fors_extract.startwavelength",
00330                                 CPL_TYPE_DOUBLE,
00331                                 "Start wavelength in spectral extraction",
00332                                 "fors.fors_extract",
00333                                 0.0);
00334     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00335     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00336     cpl_parameterlist_append(recipe->parameters, p);
00337 
00338     /*
00339      * End wavelength for spectral extraction
00340      */
00341 
00342     p = cpl_parameter_new_value("fors.fors_extract.endwavelength",
00343                                 CPL_TYPE_DOUBLE,
00344                                 "End wavelength in spectral extraction",
00345                                 "fors.fors_extract",
00346                                 0.0);
00347     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00348     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00349     cpl_parameterlist_append(recipe->parameters, p);
00350 
00351     /*
00352      * Flux conservation
00353      */
00354 
00355     p = cpl_parameter_new_value("fors.fors_extract.flux",
00356                                 CPL_TYPE_BOOL,
00357                                 "Apply flux conservation",
00358                                 "fors.fors_extract",
00359                                 TRUE);
00360     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00361     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00362     cpl_parameterlist_append(recipe->parameters, p);
00363 
00364     /*
00365      * Apply flat field
00366      */
00367 
00368     p = cpl_parameter_new_value("fors.fors_extract.flatfield",
00369                                 CPL_TYPE_BOOL,
00370                                 "Apply flat field",
00371                                 "fors.fors_extract",
00372                                 FALSE);
00373     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield");
00374     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00375     cpl_parameterlist_append(recipe->parameters, p);
00376 
00377     /*
00378      * Global sky subtraction
00379      */
00380 
00381     p = cpl_parameter_new_value("fors.fors_extract.skyglobal",
00382                                 CPL_TYPE_BOOL,
00383                                 "Subtract global sky spectrum from CCD",
00384                                 "fors.fors_extract",
00385                                 FALSE);
00386     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyglobal");
00387     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00388     cpl_parameterlist_append(recipe->parameters, p);
00389 
00390     /*
00391      * Local sky subtraction on extracted spectra
00392      */
00393 
00394 /*** New sky subtraction (search NSS)
00395     p = cpl_parameter_new_value("fors.fors_extract.skymedian",
00396                                 CPL_TYPE_INT,
00397                                 "Degree of sky fitting polynomial for "
00398                                 "sky subtraction from extracted "
00399                                 "slit spectra (MOS/MXU only, -1 to disable it)",
00400                                 "fors.fors_extract",
00401                                 0);
00402     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian");
00403     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00404     cpl_parameterlist_append(recipe->parameters, p);
00405 ***/
00406 
00407     p = cpl_parameter_new_value("fors.fors_extract.skymedian",
00408                                 CPL_TYPE_BOOL,
00409                                 "Sky subtraction from extracted slit spectra",
00410                                 "fors.fors_extract",
00411                                 FALSE);
00412     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian");
00413     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00414     cpl_parameterlist_append(recipe->parameters, p);
00415 
00416     /*
00417      * Local sky subtraction on CCD spectra
00418      */
00419 
00420     p = cpl_parameter_new_value("fors.fors_extract.skylocal",
00421                                 CPL_TYPE_BOOL,
00422                                 "Sky subtraction from CCD slit spectra",
00423                                 "fors.fors_extract",
00424                                 TRUE);
00425     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal");
00426     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00427     cpl_parameterlist_append(recipe->parameters, p);
00428 
00429     /*
00430      * Cosmic rays removal
00431      */
00432 
00433     p = cpl_parameter_new_value("fors.fors_extract.cosmics",
00434                                 CPL_TYPE_BOOL,
00435                                 "Eliminate cosmic rays hits (only if global "
00436                                 "sky subtraction is also requested)",
00437                                 "fors.fors_extract",
00438                                 FALSE);
00439     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics");
00440     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00441     cpl_parameterlist_append(recipe->parameters, p);
00442 
00443     /*
00444      * Slit margin
00445      */
00446 
00447     p = cpl_parameter_new_value("fors.fors_extract.slit_margin",
00448                                 CPL_TYPE_INT,
00449                                 "Number of pixels to exclude at each slit "
00450                                 "in object detection and extraction",
00451                                 "fors.fors_extract",
00452                                 3);
00453     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin");
00454     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00455     cpl_parameterlist_append(recipe->parameters, p);
00456 
00457     /*
00458      * Extraction radius
00459      */
00460 
00461     p = cpl_parameter_new_value("fors.fors_extract.ext_radius",
00462                                 CPL_TYPE_INT,
00463                                 "Maximum extraction radius for detected "
00464                                 "objects (pixel)",
00465                                 "fors.fors_extract",
00466                                 6);
00467     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius");
00468     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00469     cpl_parameterlist_append(recipe->parameters, p);
00470 
00471     /*
00472      * Contamination radius
00473      */
00474 
00475     p = cpl_parameter_new_value("fors.fors_extract.cont_radius",
00476                                 CPL_TYPE_INT,
00477                                 "Minimum distance at which two objects "
00478                                 "of equal luminosity do not contaminate "
00479                                 "each other (pixel)",
00480                                 "fors.fors_extract",
00481                                 0);
00482     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius");
00483     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00484     cpl_parameterlist_append(recipe->parameters, p);
00485 
00486     /*
00487      * Object extraction method
00488      */
00489 
00490     p = cpl_parameter_new_value("fors.fors_extract.ext_mode",
00491                                 CPL_TYPE_INT,
00492                                 "Object extraction method: 0 = aperture, "
00493                                 "1 = Horne optimal extraction",
00494                                 "fors.fors_extract",
00495                                 1);
00496     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode");
00497     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00498     cpl_parameterlist_append(recipe->parameters, p);
00499 
00500     /*
00501      * Normalise output by exposure time
00502      */
00503 
00504     p = cpl_parameter_new_value("fors.fors_extract.time_normalise",
00505                                 CPL_TYPE_BOOL,
00506                                 "Normalise output spectra by the exposure time",
00507                                 "fors.fors_extract",
00508                                 TRUE);
00509     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise");
00510     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00511     cpl_parameterlist_append(recipe->parameters, p);
00512 
00513     return 0;
00514 }
00515 
00516 
00525 static int fors_extract_exec(cpl_plugin *plugin)
00526 {
00527     cpl_recipe *recipe;
00528     
00529     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00530         recipe = (cpl_recipe *)plugin;
00531     else 
00532         return -1;
00533 
00534     return fors_extract(recipe->parameters, recipe->frames);
00535 }
00536 
00537 
00546 static int fors_extract_destroy(cpl_plugin *plugin)
00547 {
00548     cpl_recipe *recipe;
00549     
00550     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00551         recipe = (cpl_recipe *)plugin;
00552     else 
00553         return -1;
00554 
00555     cpl_parameterlist_delete(recipe->parameters); 
00556 
00557     return 0;
00558 }
00559 
00560 
00570 static int fors_extract(cpl_parameterlist *parlist, cpl_frameset *frameset)
00571 {
00572 
00573     const char *recipe = "fors_extract";
00574 
00575 
00576     /*
00577      * Input parameters
00578      */
00579 
00580     double      dispersion;
00581     int         skyalign;
00582     const char *wcolumn;
00583     double      startwavelength;
00584     double      endwavelength;
00585     int         flux;
00586     int         flatfield;
00587     int         skyglobal;
00588     int         skylocal;
00589     int         skymedian;
00590     int         cosmics;
00591     int         slit_margin;
00592     int         ext_radius;
00593     int         cont_radius;
00594     int         ext_mode;
00595     int         time_normalise;
00596 
00597 
00598     /*
00599      * CPL objects
00600      */
00601 
00602     cpl_imagelist    *all_science;
00603     cpl_image       **images;
00604 
00605     cpl_image        *bias           = NULL;
00606     cpl_image        *norm_flat      = NULL;
00607     cpl_image        *spectra        = NULL;
00608     cpl_image        *rectified      = NULL;
00609     cpl_image        *coordinate     = NULL;
00610     cpl_image        *rainbow        = NULL;
00611     cpl_image        *mapped         = NULL;
00612     cpl_image        *mapped_sky     = NULL;
00613     cpl_image        *mapped_cleaned = NULL;
00614     cpl_image        *smapped        = NULL;
00615     cpl_image        *wavemap        = NULL;
00616     cpl_image        *skymap         = NULL;
00617     cpl_image        *skylocalmap    = NULL;
00618     cpl_image        *dummy          = NULL;
00619 
00620     cpl_table        *grism_table    = NULL;
00621     cpl_table        *overscans      = NULL;
00622     cpl_table        *wavelengths    = NULL;
00623     cpl_table        *idscoeff       = NULL;
00624     cpl_table        *slits          = NULL;
00625     cpl_table        *maskslits      = NULL;
00626     cpl_table        *polytraces     = NULL;
00627     cpl_table        *offsets        = NULL;
00628     cpl_table        *sky            = NULL;
00629     cpl_table        *global         = NULL;
00630 
00631     cpl_vector       *lines          = NULL;
00632 
00633     cpl_propertylist *header         = NULL;
00634     cpl_propertylist *save_header    = NULL;
00635 
00636     /*
00637      * Auxiliary variables
00638      */
00639 
00640     char         version[80];
00641     char        *instrume = NULL;
00642     char        *wheel4 = NULL;
00643     const char  *science_tag;
00644     const char  *master_norm_flat_tag;
00645     const char  *disp_coeff_sky_tag;
00646     const char  *wavelength_map_sky_tag;
00647     const char  *reduced_science_tag;
00648     const char  *reduced_sky_tag;
00649     const char  *reduced_error_tag;
00650     const char  *mapped_science_tag;
00651     const char  *unmapped_science_tag;
00652     const char  *mapped_science_sky_tag;
00653     const char  *mapped_sky_tag;
00654     const char  *unmapped_sky_tag;
00655     const char  *global_sky_spectrum_tag;
00656     const char  *object_table_tag;
00657     const char  *skylines_offsets_tag;
00658     const char  *global_distortion_tag = "MASTER_DISTORTION_TABLE";
00659     char        *coll;
00660     int         mxu, mos, lss;
00661     int         nscience;
00662     double     *exptime = NULL;
00663     double      alltime;
00664     double      mean_rms;
00665     int         nlines;
00666     int         rebin;
00667     double     *line;
00668     int         nx, ny;
00669     double      reference;
00670     double      gain;
00671     double      ron;
00672     int         standard;
00673     int         highres;
00674     int         narrow = 0;
00675     int         i;
00676 
00677 
00678     snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00679 
00680     cpl_msg_set_indentation(2);
00681 
00682     if (dfs_files_dont_exist(frameset))
00683         fors_extract_exit(NULL);
00684 
00685     /* 
00686      * Get configuration parameters
00687      */
00688 
00689     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00690     cpl_msg_indent_more();
00691 
00692     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00693         fors_extract_exit("Too many in input: GRISM_TABLE");
00694 
00695     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00696 
00697     dispersion = dfs_get_parameter_double(parlist, 
00698                     "fors.fors_extract.dispersion", grism_table);
00699 
00700     if (dispersion <= 0.0)
00701         fors_extract_exit("Invalid resampling step");
00702 
00703     skyalign = dfs_get_parameter_int(parlist, 
00704                     "fors.fors_extract.skyalign", NULL);
00705 
00706     if (skyalign > 2)
00707         fors_extract_exit("Max polynomial degree for sky alignment is 2");
00708 
00709     wcolumn = dfs_get_parameter_string(parlist, 
00710                     "fors.fors_extract.wcolumn", NULL);
00711 
00712     startwavelength = dfs_get_parameter_double(parlist, 
00713                     "fors.fors_extract.startwavelength", grism_table);
00714     if (startwavelength < 3000.0 || startwavelength > 13000.0)
00715         fors_extract_exit("Invalid wavelength");
00716 
00717     endwavelength = dfs_get_parameter_double(parlist, 
00718                     "fors.fors_extract.endwavelength", grism_table);
00719     if (endwavelength < 3000.0 || endwavelength > 13000.0)
00720         fors_extract_exit("Invalid wavelength");
00721 
00722     if (endwavelength - startwavelength <= 0.0)
00723         fors_extract_exit("Invalid wavelength interval");
00724 
00725     flux = dfs_get_parameter_bool(parlist, "fors.fors_extract.flux", NULL);
00726 
00727     flatfield = dfs_get_parameter_bool(parlist, "fors.fors_extract.flatfield", 
00728                                        NULL);
00729 
00730     skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_extract.skyglobal", 
00731                                        NULL);
00732     skylocal  = dfs_get_parameter_bool(parlist, "fors.fors_extract.skylocal", 
00733                                        NULL);
00734     skymedian = dfs_get_parameter_bool(parlist, "fors.fors_extract.skymedian", 
00735                                        NULL);
00736 /* NSS
00737     skymedian = dfs_get_parameter_int(parlist, "fors.fors_extract.skymedian", 
00738                                        NULL);
00739 */
00740 
00741     if (skylocal && skyglobal)
00742         fors_extract_exit("Cannot apply both local and global sky subtraction");
00743 
00744     if (skylocal && skymedian)
00745         fors_extract_exit("Cannot apply sky subtraction both on extracted "
00746                           "and non-extracted spectra");
00747 
00748     cosmics = dfs_get_parameter_bool(parlist, 
00749                                      "fors.fors_extract.cosmics", NULL);
00750 
00751     if (cosmics)
00752         if (!(skyglobal || skylocal))
00753             fors_extract_exit("Cosmic rays correction requires "
00754                               "either skylocal=true or skyglobal=true");
00755 
00756     slit_margin = dfs_get_parameter_int(parlist, 
00757                                         "fors.fors_extract.slit_margin",
00758                                         NULL);
00759     if (slit_margin < 0)
00760         fors_extract_exit("Value must be zero or positive");
00761 
00762     ext_radius = dfs_get_parameter_int(parlist, 
00763                                        "fors.fors_extract.ext_radius",
00764                                        NULL);
00765     if (ext_radius < 0)
00766         fors_extract_exit("Value must be zero or positive");
00767 
00768     cont_radius = dfs_get_parameter_int(parlist, 
00769                                         "fors.fors_extract.cont_radius",
00770                                        NULL);
00771     if (cont_radius < 0)
00772         fors_extract_exit("Value must be zero or positive");
00773 
00774     ext_mode = dfs_get_parameter_int(parlist, "fors.fors_extract.ext_mode",
00775                                        NULL);
00776     if (ext_mode < 0 || ext_mode > 1)
00777         fors_extract_exit("Invalid object extraction mode");
00778 
00779     time_normalise = dfs_get_parameter_bool(parlist, 
00780                              "fors.fors_extract.time_normalise", NULL);
00781 
00782     cpl_table_delete(grism_table); grism_table = NULL;
00783 
00784     if (cpl_error_get_code())
00785         fors_extract_exit("Failure getting the configuration parameters");
00786 
00787     
00788     /* 
00789      * Check input set-of-frames
00790      */
00791 
00792     cpl_msg_indent_less();
00793     cpl_msg_info(recipe, "Check input set-of-frames:");
00794     cpl_msg_indent_more();
00795 
00796     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00797         fors_extract_exit("Input frames are not from the same grism");
00798 
00799     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00800         fors_extract_exit("Input frames are not from the same filter");
00801 
00802     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00803         fors_extract_exit("Input frames are not from the same chip");
00804 
00805     mxu = cpl_frameset_count_tags(frameset, "SCIENCE_MXU");
00806     mos = cpl_frameset_count_tags(frameset, "SCIENCE_MOS");
00807     lss = cpl_frameset_count_tags(frameset, "SCIENCE_LSS");
00808     standard = 0;
00809 
00810     if (mxu + mos + lss == 0) {
00811         mxu = cpl_frameset_count_tags(frameset, "STANDARD_MXU");
00812         mos = cpl_frameset_count_tags(frameset, "STANDARD_MOS");
00813         lss = cpl_frameset_count_tags(frameset, "STANDARD_LSS");
00814         standard = 1;
00815     }
00816 
00817     if (mxu + mos + lss == 0)
00818         fors_extract_exit("Missing input scientific frame");
00819 
00820     nscience = mxu + mos + lss;
00821 
00822     if (mxu && mxu < nscience)
00823         fors_extract_exit("Input scientific frames must be of the same type"); 
00824 
00825     if (mos && mos < nscience)
00826         fors_extract_exit("Input scientific frames must be of the same type"); 
00827 
00828     if (lss && lss < nscience)
00829         fors_extract_exit("Input scientific frames must be of the same type"); 
00830 
00831     if (mxu) {
00832         if (standard) {
00833             cpl_msg_info(recipe, "MXU data found");
00834             science_tag            = "STANDARD_MXU";
00835             reduced_science_tag    = "REDUCED_STD_MXU";
00836             unmapped_science_tag   = "UNMAPPED_STD_MXU";
00837             mapped_science_tag     = "MAPPED_STD_MXU";
00838             mapped_science_sky_tag = "MAPPED_ALL_STD_MXU";
00839             skylines_offsets_tag   = "SKY_SHIFTS_SLIT_STD_MXU";
00840             wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_MXU";
00841             disp_coeff_sky_tag     = "DISP_COEFF_STD_MXU";
00842             mapped_sky_tag         = "MAPPED_SKY_STD_MXU";
00843             unmapped_sky_tag       = "UNMAPPED_SKY_STD_MXU";
00844             object_table_tag       = "OBJECT_TABLE_STD_MXU";
00845             reduced_sky_tag        = "REDUCED_SKY_STD_MXU";
00846             reduced_error_tag      = "REDUCED_ERROR_STD_MXU";
00847         }
00848         else {
00849             cpl_msg_info(recipe, "MXU data found");
00850             science_tag            = "SCIENCE_MXU";
00851             reduced_science_tag    = "REDUCED_SCI_MXU";
00852             unmapped_science_tag   = "UNMAPPED_SCI_MXU";
00853             mapped_science_tag     = "MAPPED_SCI_MXU";
00854             mapped_science_sky_tag = "MAPPED_ALL_SCI_MXU";
00855             skylines_offsets_tag   = "SKY_SHIFTS_SLIT_SCI_MXU";
00856             wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_MXU";
00857             disp_coeff_sky_tag     = "DISP_COEFF_SCI_MXU";
00858             mapped_sky_tag         = "MAPPED_SKY_SCI_MXU";
00859             unmapped_sky_tag       = "UNMAPPED_SKY_SCI_MXU";
00860             object_table_tag       = "OBJECT_TABLE_SCI_MXU";
00861             reduced_sky_tag        = "REDUCED_SKY_SCI_MXU";
00862             reduced_error_tag      = "REDUCED_ERROR_SCI_MXU";
00863         }
00864 
00865         master_norm_flat_tag    = "MASTER_NORM_FLAT_MXU";
00866         global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_MXU";
00867 
00868         if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
00869             master_norm_flat_tag    = "MASTER_NORM_FLAT_LONG_MXU";
00870         }
00871     }
00872 
00873     if (lss) {
00874 
00875         if (cosmics && !skyglobal)
00876             fors_extract_exit("Cosmic rays correction for LSS "
00877                               "data requires --skyglobal=true");
00878 
00879         cpl_msg_info(recipe, "LSS data found");
00880 
00881         if (standard) {
00882             science_tag             = "STANDARD_LSS";
00883             reduced_science_tag     = "REDUCED_STD_LSS";
00884             unmapped_science_tag    = "UNMAPPED_STD_LSS";
00885             mapped_science_tag      = "MAPPED_STD_LSS";
00886             mapped_science_sky_tag  = "MAPPED_ALL_STD_LSS";
00887             skylines_offsets_tag    = "SKY_SHIFTS_LONG_STD_LSS";
00888             wavelength_map_sky_tag  = "WAVELENGTH_MAP_STD_LSS";
00889             disp_coeff_sky_tag      = "DISP_COEFF_STD_LSS";
00890             mapped_sky_tag          = "MAPPED_SKY_STD_LSS";
00891             unmapped_sky_tag        = "UNMAPPED_SKY_STD_LSS";
00892             object_table_tag        = "OBJECT_TABLE_STD_LSS";
00893             reduced_sky_tag         = "REDUCED_SKY_STD_LSS";
00894             reduced_error_tag       = "REDUCED_ERROR_STD_LSS";
00895         }
00896         else {
00897             science_tag             = "SCIENCE_LSS";
00898             reduced_science_tag     = "REDUCED_SCI_LSS";
00899             unmapped_science_tag    = "UNMAPPED_SCI_LSS";
00900             mapped_science_tag      = "MAPPED_SCI_LSS";
00901             mapped_science_sky_tag  = "MAPPED_ALL_SCI_LSS";
00902             skylines_offsets_tag    = "SKY_SHIFTS_LONG_SCI_LSS";
00903             wavelength_map_sky_tag  = "WAVELENGTH_MAP_SCI_LSS";
00904             disp_coeff_sky_tag      = "DISP_COEFF_SCI_LSS";
00905             mapped_sky_tag          = "MAPPED_SKY_SCI_LSS";
00906             unmapped_sky_tag        = "UNMAPPED_SKY_SCI_LSS";
00907             object_table_tag        = "OBJECT_TABLE_SCI_LSS";
00908             reduced_sky_tag         = "REDUCED_SKY_SCI_LSS";
00909             reduced_error_tag       = "REDUCED_ERROR_SCI_LSS";
00910         }
00911 
00912         master_norm_flat_tag    = "MASTER_NORM_FLAT_LSS";
00913         global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_LSS";
00914     }
00915 
00916     if (mos) {
00917         cpl_msg_info(recipe, "MOS data found");
00918         if (standard) {
00919             science_tag             = "STANDARD_MOS";
00920             reduced_science_tag     = "REDUCED_STD_MOS";
00921             unmapped_science_tag    = "UNMAPPED_STD_MOS";
00922             mapped_science_tag      = "MAPPED_STD_MOS";
00923             mapped_science_sky_tag  = "MAPPED_ALL_STD_MOS";
00924             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_STD_MOS";
00925             wavelength_map_sky_tag  = "WAVELENGTH_MAP_STD_MOS";
00926             disp_coeff_sky_tag      = "DISP_COEFF_STD_MOS";
00927             mapped_sky_tag          = "MAPPED_SKY_STD_MOS";
00928             unmapped_sky_tag        = "UNMAPPED_SKY_STD_MOS";
00929             object_table_tag        = "OBJECT_TABLE_STD_MOS";
00930             reduced_sky_tag         = "REDUCED_SKY_STD_MOS";
00931             reduced_error_tag       = "REDUCED_ERROR_STD_MOS";
00932         }
00933         else {
00934             science_tag             = "SCIENCE_MOS";
00935             reduced_science_tag     = "REDUCED_SCI_MOS";
00936             unmapped_science_tag    = "UNMAPPED_SCI_MOS";
00937             mapped_science_tag      = "MAPPED_SCI_MOS";
00938             mapped_science_sky_tag  = "MAPPED_ALL_SCI_MOS";
00939             skylines_offsets_tag    = "SKY_SHIFTS_SLIT_SCI_MOS";
00940             wavelength_map_sky_tag  = "WAVELENGTH_MAP_SCI_MOS";
00941             disp_coeff_sky_tag      = "DISP_COEFF_SCI_MOS";
00942             mapped_sky_tag          = "MAPPED_SKY_SCI_MOS";
00943             unmapped_sky_tag        = "UNMAPPED_SKY_SCI_MOS";
00944             object_table_tag        = "OBJECT_TABLE_SCI_MOS";
00945             reduced_sky_tag         = "REDUCED_SKY_SCI_MOS";
00946             reduced_error_tag       = "REDUCED_ERROR_SCI_MOS";
00947         }
00948 
00949         master_norm_flat_tag    = "MASTER_NORM_FLAT_MOS";
00950         global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_MOS";
00951 
00952         if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
00953             master_norm_flat_tag    = "MASTER_NORM_FLAT_LONG_MOS";
00954         }
00955     }
00956 
00957     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
00958         fors_extract_exit("Missing required input: MASTER_BIAS");
00959 
00960     if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00961         fors_extract_exit("Too many in input: MASTER_BIAS");
00962 
00963     if (skyalign >= 0)
00964         if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
00965             fors_extract_exit("Too many in input: MASTER_SKYLINECAT");
00966 
00967     if (cpl_frameset_count_tags(frameset, global_distortion_tag) == 0)
00968         fors_extract_exit("Missing required input: MASTER_DISTORTION_TABLE");
00969 
00970     if (cpl_frameset_count_tags(frameset, global_distortion_tag) > 1)
00971         fors_extract_exit("Too many in input: MASTER_DISTORTION_TABLE");
00972 
00973     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
00974         if (flatfield) {
00975             cpl_msg_error(recipe, "Too many in input: %s", 
00976                           master_norm_flat_tag);
00977             fors_extract_exit(NULL);
00978         }
00979         else {
00980             cpl_msg_warning(recipe, "%s in input are ignored, "
00981                             "since flat field correction was not requested", 
00982                             master_norm_flat_tag);
00983         }
00984     }
00985 
00986     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
00987         if (!flatfield) {
00988             cpl_msg_warning(recipe, "%s in input is ignored, "
00989                             "since flat field correction was not requested", 
00990                             master_norm_flat_tag);
00991         }
00992     }
00993 
00994     if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
00995         if (flatfield) {
00996             cpl_msg_error(recipe, "Flat field correction was requested, "
00997                           "but no %s are found in input",
00998                           master_norm_flat_tag);
00999             fors_extract_exit(NULL);
01000         }
01001     }
01002 
01003     cpl_msg_indent_less();
01004 
01005 
01006     /*
01007      * Loading input data
01008      */
01009 
01010     exptime = cpl_calloc(nscience, sizeof(double));
01011 
01012     if (nscience > 1) {
01013 
01014         cpl_msg_info(recipe, "Load %d scientific frames and median them...",
01015                      nscience);
01016         cpl_msg_indent_more();
01017 
01018         all_science = cpl_imagelist_new();
01019 
01020         header = dfs_load_header(frameset, science_tag, 0);
01021 
01022         if (header == NULL)
01023             fors_extract_exit("Cannot load scientific frame header");
01024 
01025         alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME");
01026 
01027         if (cpl_error_get_code() != CPL_ERROR_NONE)
01028             fors_extract_exit("Missing keyword EXPTIME in scientific "
01029                               "frame header");
01030 
01031         cpl_propertylist_delete(header); header = NULL;
01032 
01033         cpl_msg_info(recipe, "Scientific frame 1 exposure time: %.2f s", 
01034                      exptime[0]);
01035 
01036         for (i = 1; i < nscience; i++) {
01037 
01038             header = dfs_load_header(frameset, NULL, 0);
01039 
01040             if (header == NULL)
01041                 fors_extract_exit("Cannot load scientific frame header");
01042     
01043             exptime[i] = cpl_propertylist_get_double(header, "EXPTIME");
01044 
01045             alltime += exptime[i];
01046     
01047             if (cpl_error_get_code() != CPL_ERROR_NONE)
01048                 fors_extract_exit("Missing keyword EXPTIME in scientific "
01049                                   "frame header");
01050     
01051             cpl_propertylist_delete(header); header = NULL;
01052 
01053             cpl_msg_info(recipe, "Scientific frame %d exposure time: %.2f s", 
01054                          i+1, exptime[i]);
01055         }
01056 
01057         spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
01058 
01059         if (spectra == NULL)
01060             fors_extract_exit("Cannot load scientific frame");
01061 
01062         cpl_image_divide_scalar(spectra, exptime[0]);
01063         cpl_imagelist_set(all_science, spectra, 0); spectra = NULL;
01064 
01065         for (i = 1; i < nscience; i++) {
01066 
01067             spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01068 
01069             if (spectra) {
01070                 cpl_image_divide_scalar(spectra, exptime[i]);
01071                 cpl_imagelist_set(all_science, spectra, i); spectra = NULL;
01072             }
01073             else
01074                 fors_extract_exit("Cannot load scientific frame");
01075 
01076         }
01077 
01078         spectra = cpl_imagelist_collapse_median_create(all_science);
01079         cpl_image_multiply_scalar(spectra, alltime);
01080 
01081         cpl_imagelist_delete(all_science);
01082     }
01083     else {
01084         cpl_msg_info(recipe, "Load scientific exposure...");
01085         cpl_msg_indent_more();
01086 
01087         header = dfs_load_header(frameset, science_tag, 0);
01088 
01089         if (header == NULL)
01090             fors_extract_exit("Cannot load scientific frame header");
01091 
01092 
01093         /*
01094          * Insert here a check on supported filters:
01095          */
01096 
01097         wheel4 = (char *)cpl_propertylist_get_string(header,
01098                                                      "ESO INS OPTI9 TYPE");
01099         if (cpl_error_get_code() != CPL_ERROR_NONE) {
01100             fors_extract_exit("Missing ESO INS OPTI9 TYPE in flat header");
01101         }
01102 
01103         if (strcmp("FILT", wheel4) == 0) {
01104             wheel4 = (char *)cpl_propertylist_get_string(header,
01105                                                          "ESO INS OPTI9 NAME");
01106             cpl_msg_error(recipe, "Unsupported filter: %s", wheel4);
01107             fors_extract_exit(NULL);
01108         }
01109 
01110 
01111         alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME");
01112 
01113         if (cpl_error_get_code() != CPL_ERROR_NONE)
01114             fors_extract_exit("Missing keyword EXPTIME in scientific "
01115                               "frame header");
01116 
01117         cpl_propertylist_delete(header); header = NULL;
01118 
01119         cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 
01120                      exptime[0]);
01121 
01122         spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
01123     }
01124 
01125     if (spectra == NULL)
01126         fors_extract_exit("Cannot load scientific frame");
01127 
01128     cpl_free(exptime); exptime = NULL;
01129 
01130     cpl_msg_indent_less();
01131 
01132 
01133     /*
01134      * Get the reference wavelength and the rebin factor along the
01135      * dispersion direction from a scientific exposure
01136      */
01137 
01138     header = dfs_load_header(frameset, science_tag, 0);
01139 
01140     if (header == NULL)
01141         fors_extract_exit("Cannot load scientific frame header");
01142 
01143     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
01144     if (instrume == NULL)
01145         fors_extract_exit("Missing keyword INSTRUME in sientific header");
01146     instrume = cpl_strdup(instrume);
01147 
01148     if (instrume[4] == '1')
01149         snprintf(version, 80, "%s/%s", "fors1", VERSION);
01150     if (instrume[4] == '2')
01151         snprintf(version, 80, "%s/%s", "fors2", VERSION);
01152 
01153     cpl_free(instrume); instrume = NULL;
01154 
01155     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
01156 
01157     if (cpl_error_get_code() != CPL_ERROR_NONE)
01158         fors_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific "
01159                         "frame header");
01160 
01161     if (reference < 3000.0)   /* Perhaps in nanometers... */
01162         reference *= 10;
01163 
01164     if (reference < 3000.0 || reference > 13000.0) {
01165         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01166                       "keyword ESO INS GRIS1 WLEN in scientific frame header",
01167                       reference);
01168         fors_extract_exit(NULL);
01169     }
01170 
01171     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01172 
01173     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01174 
01175     if (cpl_error_get_code() != CPL_ERROR_NONE)
01176         fors_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific "
01177                         "frame header");
01178 
01179     if (rebin != 1) {
01180         dispersion *= rebin;
01181         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01182                         "resampling step used is %f A/pixel", rebin, 
01183                         dispersion);
01184     }
01185 
01186     gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01187 
01188     if (cpl_error_get_code() != CPL_ERROR_NONE)
01189         fors_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific "
01190                           "frame header");
01191 
01192     cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01193 
01194     ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01195 
01196     if (cpl_error_get_code() != CPL_ERROR_NONE)
01197         fors_extract_exit("Missing keyword ESO DET OUT1 RON in scientific "
01198                           "frame header");
01199 
01200     ron /= gain;     /* Convert from electrons to ADU */
01201 
01202     cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
01203 
01204     coll = (char *)cpl_propertylist_get_string(header, "ESO INS COLL NAME");
01205 
01206     if (cpl_error_get_code() != CPL_ERROR_NONE)
01207         fors_extract_exit("Missing keyword ESO INS COLL NAME in scientific "
01208                           "frame header");
01209 
01210     cpl_msg_info(recipe, "The collimator is : %s", coll);
01211 
01212     if (strcmp(coll, "COLL_HR") == 0)
01213         fors_extract_exit("HR collimator is not yet supported by this recipe");
01214     
01215 
01216     if (mos)
01217         maskslits = mos_load_slits_fors_mos(header);
01218     else if (lss)
01219         maskslits = mos_load_slits_fors_lss(header);
01220     else
01221         maskslits = mos_load_slits_fors_mxu(header);
01222 
01223     if (lss) {
01224         if (skylocal) {
01225             if (cosmics)
01226                 fors_extract_exit("Cosmic rays correction for LSS "
01227                                   "data requires --skyglobal=true");
01228             skymedian = skylocal;
01229             skylocal = 0;
01230         }
01231     }
01232 
01233     global = dfs_load_table(frameset, global_distortion_tag, 1);
01234     if (global == NULL)
01235         fors_extract_exit("Cannot load global distortion table");
01236 
01237     /* Leave the header on for the next step... */
01238 
01239 
01240     /*
01241      * Remove the master bias
01242      */
01243 
01244     cpl_msg_info(recipe, "Remove the master bias...");
01245 
01246     bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
01247 
01248     if (bias == NULL)
01249         fors_extract_exit("Cannot load master bias");
01250 
01251     overscans = mos_load_overscans_vimos(header, 1);
01252     cpl_propertylist_delete(header); header = NULL;
01253     dummy = mos_remove_bias(spectra, bias, overscans);
01254     cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
01255     cpl_image_delete(bias); bias = NULL;
01256     cpl_table_delete(overscans); overscans = NULL;
01257 
01258     if (spectra == NULL)
01259         fors_extract_exit("Cannot remove bias from scientific frame");
01260 
01261     nx = cpl_image_get_size_x(spectra);
01262     ny = cpl_image_get_size_y(spectra);
01263 
01264     if (ny == 400 && nx == 2048)
01265         narrow = 1;
01266 
01267     if (narrow) {
01268         ny = 2048;
01269         dummy = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01270         cpl_image_copy(dummy, spectra, 1, 825);     /* (2048 - 400)/2 + 1 */
01271         if (cpl_error_get_code())
01272             fors_extract_exit("Problems expanding scientific image");
01273         cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
01274     }
01275 
01276     cpl_msg_indent_less();
01277     cpl_msg_info(recipe, "Load normalised flat field (if present)...");
01278     cpl_msg_indent_more();
01279 
01280     if (flatfield) {
01281 
01282         norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 
01283                                    CPL_TYPE_FLOAT, 0, 1);
01284 
01285         if (norm_flat) {
01286             if (narrow) {
01287                 dummy = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01288                 cpl_image_copy(dummy, norm_flat, 1, 825);
01289                 if (cpl_error_get_code())
01290                     fors_extract_exit("Problems expanding flat image");
01291                 cpl_image_delete(norm_flat); norm_flat = dummy; dummy = NULL;
01292             }
01293             cpl_msg_info(recipe, "Apply flat field correction...");
01294             if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
01295                 cpl_msg_error(recipe, "Failure of flat field correction: %s",
01296                               cpl_error_get_message());
01297                 fors_extract_exit(NULL);
01298             }
01299             cpl_image_delete(norm_flat); norm_flat = NULL;
01300         }
01301         else {
01302             cpl_msg_error(recipe, "Cannot load input %s for flat field "
01303                           "correction", master_norm_flat_tag);
01304             fors_extract_exit(NULL);
01305         }
01306 
01307     }
01308 
01309 
01310     if (skyalign >= 0) {
01311         cpl_msg_indent_less();
01312         cpl_msg_info(recipe, "Load input sky line catalog...");
01313         cpl_msg_indent_more();
01314 
01315         wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
01316 
01317         if (wavelengths) {
01318 
01319             /*
01320              * Cast the wavelengths into a (double precision) CPL vector
01321              */
01322 
01323             nlines = cpl_table_get_nrow(wavelengths);
01324 
01325             if (nlines == 0)
01326                 fors_extract_exit("Empty input sky line catalog");
01327 
01328             if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01329                 cpl_msg_error(recipe, "Missing column %s in input line "
01330                               "catalog table", wcolumn);
01331                 fors_extract_exit(NULL);
01332             }
01333 
01334             line = cpl_malloc(nlines * sizeof(double));
01335     
01336             for (i = 0; i < nlines; i++)
01337                 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01338 
01339             cpl_table_delete(wavelengths); wavelengths = NULL;
01340 
01341             lines = cpl_vector_wrap(nlines, line);
01342         }
01343         else {
01344             cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
01345         }
01346     }
01347 
01348 
01349     /*
01350      * Load the slit location table, or provide a dummy one in case
01351      * of LSS data (single slit spanning whole image)
01352      */
01353 
01354     slits = mos_build_slit_location(global, maskslits, ny);
01355     if (slits == NULL)
01356         fors_extract_exit("Cannot create slits location table");
01357 
01358 
01359     /*
01360      * Load the spectral curvature table in case of MOS or MXU data
01361      */
01362 
01363     polytraces = mos_build_curv_coeff(global, maskslits, slits);
01364     if (polytraces == NULL)
01365         fors_extract_exit("Cannot create spectral curvature table");
01366 
01367     cpl_table_delete(maskslits); maskslits = NULL;
01368 
01369     cpl_msg_indent_less();
01370     cpl_msg_info(recipe, "Processing scientific spectra...");
01371     cpl_msg_indent_more();
01372 
01373     /*
01374      * This one will also generate the spatial map from the spectral 
01375      * curvature table (in the case of multislit data)
01376      */
01377 
01378     coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01379 
01380     smapped = mos_spatial_calibration(spectra, slits, polytraces, reference,
01381                                       startwavelength, endwavelength,
01382                                       dispersion, flux, coordinate);
01383 
01384 
01385     /*
01386      * Load the wavelength calibration table
01387      */
01388 
01389     idscoeff = mos_build_disp_coeff(global, slits);
01390     if (idscoeff == NULL)
01391         fors_extract_exit("Cannot create wavelength calibration table");
01392 
01393     cpl_table_delete(global); global = NULL;
01394 
01395 
01396     /*
01397      * Generate a rectified wavelength map from the wavelength calibration 
01398      * table
01399      */
01400 
01401     rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 
01402                                endwavelength);
01403 
01404     if (dispersion > 1.0)
01405         highres = 0;
01406     else
01407         highres = 1;
01408 
01409     if (skyalign >= 0) {
01410         if (skyalign) {
01411             cpl_msg_info(recipe, "Align wavelength solution to reference "
01412             "skylines applying %d order residual fit...", skyalign);
01413         }
01414         else {
01415             cpl_msg_info(recipe, "Align wavelength solution to reference "
01416             "skylines applying median offset...");
01417         }
01418 
01419         if (lss) {
01420             offsets = mos_wavelength_align_lss(smapped, reference, 
01421                                                startwavelength, endwavelength, 
01422                                                idscoeff, lines, highres, 
01423                                                skyalign, rainbow, 4);
01424         }
01425         else {
01426             offsets = mos_wavelength_align(smapped, slits, reference, 
01427                                            startwavelength, endwavelength, 
01428                                            idscoeff, lines, highres, skyalign, 
01429                                            rainbow, 4);
01430         }
01431 
01432         cpl_vector_delete(lines); lines = NULL;
01433 
01434         if (offsets) {
01435             if (standard)
01436                 cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01437                                 "to reference sky lines may be unreliable in "
01438                                 "this case!");
01439 
01440             if (dfs_save_table(frameset, offsets, skylines_offsets_tag, NULL, 
01441                                parlist, recipe, version))
01442                 fors_extract_exit(NULL);
01443 
01444             cpl_table_delete(offsets); offsets = NULL;
01445         }
01446         else {
01447             cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01448                             "to reference sky lines could not be done!");
01449             skyalign = -1;
01450         }
01451 
01452     }
01453 
01454     wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 
01455                                   polytraces, reference, 
01456                                   startwavelength, endwavelength,
01457                                   dispersion);
01458 
01459     cpl_image_delete(rainbow); rainbow = NULL;
01460     cpl_image_delete(coordinate); coordinate = NULL;
01461 
01462     /*
01463      * Here the wavelength calibrated slit spectra are created. This frame
01464      * contains sky_science.
01465      */
01466 
01467     mapped_sky = mos_wavelength_calibration(smapped, reference,
01468                                             startwavelength, endwavelength,
01469                                             dispersion, idscoeff, flux);
01470 
01471     cpl_msg_indent_less();
01472     cpl_msg_info(recipe, "Check applied wavelength against skylines...");
01473     cpl_msg_indent_more();
01474 
01475     mean_rms = mos_distortions_rms(mapped_sky, NULL, startwavelength,
01476                                    dispersion, 6, highres);
01477 
01478     cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
01479 
01480     mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01481 
01482     header = cpl_propertylist_new();
01483     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01484     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01485     cpl_propertylist_update_double(header, "CRVAL1", 
01486                                    startwavelength + dispersion/2);
01487     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01488     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
01489     cpl_propertylist_update_double(header, "CDELT2", 1.0); */
01490     cpl_propertylist_update_double(header, "CD1_1", dispersion);
01491     cpl_propertylist_update_double(header, "CD1_2", 0.0);
01492     cpl_propertylist_update_double(header, "CD2_1", 0.0);
01493     cpl_propertylist_update_double(header, "CD2_2", 1.0);
01494     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01495     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01496 
01497     if (time_normalise) {
01498         dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
01499         if (dfs_save_image(frameset, dummy, mapped_science_sky_tag, header, 
01500                            parlist, recipe, version))
01501             fors_extract_exit(NULL);
01502         cpl_image_delete(dummy); dummy = NULL;
01503     }
01504     else {
01505         if (dfs_save_image(frameset, mapped_sky, mapped_science_sky_tag, 
01506                            header, parlist, recipe, version))
01507             fors_extract_exit(NULL);
01508     }
01509 
01510 /*    if (skyglobal == 0 && skymedian < 0) {    NSS */
01511     if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
01512         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01513     }
01514 
01515     if (skyglobal || skylocal) {
01516 
01517         cpl_msg_indent_less();
01518 
01519         if (skyglobal) {
01520             cpl_msg_info(recipe, "Global sky determination...");
01521             cpl_msg_indent_more();
01522             skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01523             sky = mos_sky_map_super(spectra, wavemap, dispersion, 
01524                                     2.0, 50, skymap);
01525             if (sky)
01526                 cpl_image_subtract(spectra, skymap);
01527             else
01528                 cpl_image_delete(skymap); skymap = NULL;
01529         }
01530         else {
01531             cpl_msg_info(recipe, "Local sky determination...");
01532             cpl_msg_indent_more();
01533             skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
01534                            startwavelength, endwavelength, dispersion);
01535         }
01536 
01537         if (skymap) {
01538             if (skyglobal) {
01539                 if (time_normalise)
01540                     cpl_table_divide_scalar(sky, "sky", alltime);
01541                 if (dfs_save_table(frameset, sky, global_sky_spectrum_tag, 
01542                                    NULL, parlist, recipe, version))
01543                     fors_extract_exit(NULL);
01544     
01545                 cpl_table_delete(sky); sky = NULL;
01546             }
01547 
01548             save_header = dfs_load_header(frameset, science_tag, 0);
01549 
01550             if (time_normalise)
01551                 cpl_image_divide_scalar(skymap, alltime);
01552             if (dfs_save_image(frameset, skymap, unmapped_sky_tag,
01553                                save_header, parlist, recipe, version))
01554                 fors_extract_exit(NULL);
01555 
01556             cpl_image_delete(skymap); skymap = NULL;
01557 
01558             if (dfs_save_image(frameset, spectra, unmapped_science_tag,
01559                                save_header, parlist, recipe, version))
01560                 fors_extract_exit(NULL);
01561 
01562             cpl_propertylist_delete(save_header); save_header = NULL;
01563 
01564             if (cosmics) {
01565                 cpl_msg_info(recipe, "Removing cosmic rays...");
01566                 mos_clean_cosmics(spectra, gain, -1., -1.);
01567             }
01568 
01569             /*
01570              * The spatially rectified image, that contained the sky,
01571              * is replaced by a sky-subtracted spatially rectified image:
01572              */
01573 
01574             cpl_image_delete(smapped); smapped = NULL;
01575 
01576             if (lss) {
01577                 smapped = cpl_image_duplicate(spectra);
01578             }
01579             else {
01580                 smapped = mos_spatial_calibration(spectra, slits, polytraces, 
01581                                                   reference, startwavelength, 
01582                                                   endwavelength, dispersion, 
01583                                                   flux, NULL);
01584             }
01585         }
01586         else {
01587             cpl_msg_warning(recipe, "Sky subtraction failure");
01588             if (cosmics)
01589                 cpl_msg_warning(recipe, "Cosmic rays removal not performed!");
01590             cosmics = skylocal = skyglobal = 0;
01591         }
01592     }
01593 
01594     cpl_image_delete(spectra); spectra = NULL;
01595     cpl_table_delete(polytraces); polytraces = NULL;
01596 
01597     if (skyalign >= 0) {
01598         save_header = dfs_load_header(frameset, science_tag, 0);
01599         if (dfs_save_image(frameset, wavemap, wavelength_map_sky_tag,
01600                            save_header, parlist, recipe, version))
01601             fors_extract_exit(NULL);
01602         cpl_propertylist_delete(save_header); save_header = NULL;
01603     }
01604 
01605     cpl_image_delete(wavemap); wavemap = NULL;
01606 
01607     mapped = mos_wavelength_calibration(smapped, reference,
01608                                         startwavelength, endwavelength,
01609                                         dispersion, idscoeff, flux);
01610 
01611     cpl_image_delete(smapped); smapped = NULL;
01612 
01613 /*    if (skymedian >= 0) {    NSS */
01614     if (skymedian) {
01615             cpl_msg_indent_less();
01616             cpl_msg_info(recipe, "Local sky determination...");
01617             cpl_msg_indent_more();
01618        
01619 /*   NSS      skylocalmap = mos_sky_local(mapped, slits, skymedian); */
01620 /*            skylocalmap = mos_sky_local(mapped, slits, 0);        */
01621             skylocalmap = mos_sky_local_old(mapped, slits);       
01622             cpl_image_subtract(mapped, skylocalmap);
01623 /*
01624             if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 
01625                                parlist, recipe, version))
01626                 fors_extract_exit(NULL);
01627 */
01628             cpl_image_delete(skylocalmap); skylocalmap = NULL;
01629     }
01630 
01631 /*    if (skyglobal || skymedian >= 0 || skylocal) {   NSS */
01632     if (skyglobal || skymedian || skylocal) {
01633 
01634         skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
01635 
01636         cpl_image_delete(mapped_sky); mapped_sky = NULL;
01637 
01638         if (time_normalise) {
01639             dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
01640             if (dfs_save_image(frameset, dummy, mapped_sky_tag, header,
01641                                parlist, recipe, version))
01642                 fors_extract_exit(NULL);
01643             cpl_image_delete(dummy); dummy = NULL;
01644         }
01645         else {
01646             if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header,
01647                                parlist, recipe, version))
01648                 fors_extract_exit(NULL);
01649         }
01650 
01651         cpl_msg_indent_less();
01652         cpl_msg_info(recipe, "Object detection...");
01653         cpl_msg_indent_more();
01654 
01655         if (cosmics || nscience > 1) {
01656             dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius, 
01657                                        cont_radius);
01658         }
01659         else {
01660             mapped_cleaned = cpl_image_duplicate(mapped);
01661             mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
01662             dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 
01663                                        ext_radius, cont_radius);
01664 
01665             cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
01666         }
01667 
01668         cpl_image_delete(dummy); dummy = NULL;
01669 
01670         if (dfs_save_table(frameset, slits, object_table_tag, NULL, parlist, 
01671                            recipe, version))
01672             fors_extract_exit(NULL);
01673 
01674         cpl_msg_indent_less();
01675         cpl_msg_info(recipe, "Object extraction...");
01676         cpl_msg_indent_more();
01677 
01678         images = mos_extract_objects(mapped, skylocalmap, slits, 
01679                                      ext_mode, ron, gain, 1);
01680 
01681         cpl_image_delete(skylocalmap); skylocalmap = NULL;
01682 
01683         if (images) {
01684             if (time_normalise)
01685                 cpl_image_divide_scalar(images[0], alltime);
01686             if (dfs_save_image(frameset, images[0], reduced_science_tag, header,
01687                                parlist, recipe, version))
01688                 fors_extract_exit(NULL);
01689             cpl_image_delete(images[0]);
01690     
01691             if (time_normalise)
01692                 cpl_image_divide_scalar(images[1], alltime);
01693             if (dfs_save_image(frameset, images[1], reduced_sky_tag, header,
01694                                parlist, recipe, version))
01695                 fors_extract_exit(NULL);
01696             cpl_image_delete(images[1]);
01697     
01698             if (time_normalise)
01699                 cpl_image_divide_scalar(images[2], alltime);
01700             if (dfs_save_image(frameset, images[2], reduced_error_tag, header,
01701                                parlist, recipe, version))
01702                 fors_extract_exit(NULL);
01703             cpl_image_delete(images[2]);
01704     
01705             cpl_free(images);
01706         }
01707         else {
01708             cpl_msg_warning(recipe, "No objects found: the products "
01709                             "%s, %s, and %s are not created", 
01710                             reduced_science_tag, reduced_sky_tag, 
01711                             reduced_error_tag);
01712         }
01713 
01714     }
01715 
01716     cpl_table_delete(slits); slits = NULL;
01717 
01718     if (skyalign >= 0) {
01719         if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag, NULL, 
01720                            parlist, recipe, version))
01721             fors_extract_exit(NULL);
01722     }
01723 
01724     cpl_table_delete(idscoeff); idscoeff = NULL;
01725 
01726 /*    if (skyglobal || skymedian >= 0) {   NSS */
01727     if (skyglobal || skymedian || skylocal) {
01728         if (time_normalise)
01729             cpl_image_divide_scalar(mapped, alltime);
01730         if (dfs_save_image(frameset, mapped, mapped_science_tag, header, 
01731                            parlist, recipe, version))
01732             fors_extract_exit(NULL);
01733     }
01734 
01735     cpl_image_delete(mapped); mapped = NULL;
01736     cpl_propertylist_delete(header); header = NULL;
01737 
01738     if (cpl_error_get_code()) {
01739         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
01740         fors_extract_exit(NULL);
01741     }
01742 
01743     return 0;
01744 }

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