fors_detect_spectra.c

00001 /* $Id: fors_detect_spectra.c,v 1.6 2010/09/14 07:38:16 cizzo Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cizzo $
00023  * $Date: 2010/09/14 07:38:16 $
00024  * $Revision: 1.6 $
00025  * $Name: fors-4_8_6 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <cpl.h>
00034 #include <moses.h>
00035 #include <fors_dfs.h>
00036 
00037 static int fors_detect_spectra_create(cpl_plugin *);
00038 static int fors_detect_spectra_exec(cpl_plugin *);
00039 static int fors_detect_spectra_destroy(cpl_plugin *);
00040 static int fors_detect_spectra(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char fors_detect_spectra_description[] =
00043 "This recipe is used to detect and locate MOS/MXU slit spectra on the CCD,\n"
00044 "applying a pattern-matching algorithm. The input spectral exposure must\n"
00045 "contain spectra with the dispersion direction approximately horizontal,\n"
00046 "with blue on the left and red on the right. Use recipe fors_wave_calib_lss\n"
00047 "for LSS data, or for MOS/MXU data where all slits have the same offset.\n"
00048 "\n"
00049 "The rows of the input spectral exposure are processed separately, one\n"
00050 "by one. First, the background continuum is removed. Second, a list of\n"
00051 "positions of reference lines candidates is created. Only peaks above a\n"
00052 "given threshold (specified by the parameter --peakdetection) are selected.\n"
00053 "Third, the pattern-matching task selects from the found peaks the ones\n"
00054 "corresponding to the reference lines, listed in the input line catalog,\n"
00055 "associating them to the appropriate wavelengths. The ensuing polynomial\n"
00056 "fit is used to locate the central wavelength of the applied grism along\n"
00057 "each image row. The contributions from all rows form an image of the\n"
00058 "location of all spectra, that can be used as a starting point for the\n"
00059 "proper modeling of the optical and spectral distortions. For more details\n"
00060 "on this reduction strategy please refer to the FORS Pipeline User's Manual.\n"
00061 "\n"
00062 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
00063 "configuration parameters to default values valid for a particular grism.\n"
00064 "Again, see the pipeline manual for more details.\n"
00065 "\n"
00066 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00067 "Input files:\n\n"
00068 "  DO category:               Type:       Explanation:         Required:\n"
00069 "  LAMP_UNBIAS_MXU            Calib       Bias subtracted arc     Y\n"
00070 "  MASTER_LINECAT             Calib       Line catalog            Y\n"
00071 "  GRISM_TABLE                Calib       Grism table             .\n\n"
00072 "Output files:\n\n"
00073 "  DO category:               Data type:  Explanation:\n"
00074 "  SLIT_MAP_MXU               FITS image  Map of central wavelength on CCD\n"
00075 "  SLIT_LOCATION_DETECT_MXU   FITS table  Slits positions on CCD\n"
00076 "  SPECTRA_DETECTION_MXU      FITS image  Check of preliminary detection\n\n";
00077 
00078 #define fors_detect_spectra_exit(message)     \
00079 {                                             \
00080 if (message) cpl_msg_error(recipe, message);  \
00081 cpl_image_delete(spectra);                    \
00082 cpl_image_delete(checkwave);                  \
00083 cpl_image_delete(refimage);                   \
00084 cpl_mask_delete(refmask);                     \
00085 cpl_table_delete(grism_table);                \
00086 cpl_table_delete(wavelengths);                \
00087 cpl_table_delete(maskslits);                  \
00088 cpl_table_delete(slits);                      \
00089 cpl_vector_delete(lines);                     \
00090 cpl_propertylist_delete(header);              \
00091 cpl_msg_indent_less();                        \
00092 return -1;                                    \
00093 }
00094 
00095 #define fors_detect_spectra_exit_memcheck(message) \
00096 {                                               \
00097 if (message) cpl_msg_info(recipe, message);     \
00098 printf("free spectra (%p)\n", spectra);         \
00099 cpl_image_delete(spectra);                      \
00100 printf("free checkwave (%p)\n", checkwave);     \
00101 cpl_image_delete(checkwave);                    \
00102 printf("free refimage (%p)\n", refimage);       \
00103 cpl_image_delete(refimage);                     \
00104 printf("free refmask (%p)\n", refmask);         \
00105 cpl_mask_delete(refmask);                       \
00106 printf("free grism_table (%p)\n", grism_table); \
00107 cpl_table_delete(grism_table);                  \
00108 printf("free wavelengths (%p)\n", wavelengths); \
00109 cpl_table_delete(wavelengths);                  \
00110 printf("free maskslits (%p)\n", maskslits);     \
00111 cpl_table_delete(maskslits);                    \
00112 printf("free slits (%p)\n", slits);             \
00113 cpl_table_delete(slits);                        \
00114 printf("free lines (%p)\n", lines);             \
00115 cpl_vector_delete(lines);                       \
00116 printf("free header (%p)\n", header);           \
00117 cpl_propertylist_delete(header);                \
00118 cpl_msg_indent_less();                          \
00119 return 0;                                       \
00120 }
00121 
00122 
00134 int cpl_plugin_get_info(cpl_pluginlist *list)
00135 {
00136     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00137     cpl_plugin *plugin = &recipe->interface;
00138 
00139     cpl_plugin_init(plugin,
00140                     CPL_PLUGIN_API,
00141                     FORS_BINARY_VERSION,
00142                     CPL_PLUGIN_TYPE_RECIPE,
00143                     "fors_detect_spectra",
00144                     "Detect MOS/MXU spectra on CCD",
00145                     fors_detect_spectra_description,
00146                     "Carlo Izzo",
00147                     PACKAGE_BUGREPORT,
00148     "This file is currently part of the FORS Instrument Pipeline\n"
00149     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00150     "This program is free software; you can redistribute it and/or modify\n"
00151     "it under the terms of the GNU General Public License as published by\n"
00152     "the Free Software Foundation; either version 2 of the License, or\n"
00153     "(at your option) any later version.\n\n"
00154     "This program is distributed in the hope that it will be useful,\n"
00155     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00156     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00157     "GNU General Public License for more details.\n\n"
00158     "You should have received a copy of the GNU General Public License\n"
00159     "along with this program; if not, write to the Free Software Foundation,\n"
00160     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00161                     fors_detect_spectra_create,
00162                     fors_detect_spectra_exec,
00163                     fors_detect_spectra_destroy);
00164 
00165     cpl_pluginlist_append(list, plugin);
00166     
00167     return 0;
00168 }
00169 
00170 
00181 static int fors_detect_spectra_create(cpl_plugin *plugin)
00182 {
00183     cpl_recipe    *recipe;
00184     cpl_parameter *p;
00185 
00186     /* 
00187      * Check that the plugin is part of a valid recipe 
00188      */
00189 
00190     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00191         recipe = (cpl_recipe *)plugin;
00192     else 
00193         return -1;
00194 
00195     /* 
00196      * Create the (empty) parameters list in the cpl_recipe object 
00197      */
00198 
00199     recipe->parameters = cpl_parameterlist_new(); 
00200 
00201     /*
00202      * Dispersion
00203      */
00204 
00205     p = cpl_parameter_new_value("fors.fors_detect_spectra.dispersion",
00206                                 CPL_TYPE_DOUBLE,
00207                                 "Expected spectral dispersion (Angstrom/pixel)",
00208                                 "fors.fors_detect_spectra",
00209                                 0.0);
00210     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00211     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00212     cpl_parameterlist_append(recipe->parameters, p);
00213 
00214     /*
00215      * Peak detection level
00216      */
00217 
00218     p = cpl_parameter_new_value("fors.fors_detect_spectra.peakdetection",
00219                                 CPL_TYPE_DOUBLE,
00220                                 "Initial peak detection threshold (ADU)",
00221                                 "fors.fors_detect_spectra",
00222                                 0.0);
00223     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00224     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00225     cpl_parameterlist_append(recipe->parameters, p);
00226 
00227     /*
00228      * Degree of wavelength calibration polynomial
00229      */
00230 
00231     p = cpl_parameter_new_value("fors.fors_detect_spectra.wdegree",
00232                                 CPL_TYPE_INT,
00233                                 "Degree of wavelength calibration polynomial",
00234                                 "fors.fors_detect_spectra",
00235                                 0);
00236     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00237     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00238     cpl_parameterlist_append(recipe->parameters, p);
00239 
00240     /*
00241      * Reference lines search radius
00242      */
00243 
00244     p = cpl_parameter_new_value("fors.fors_detect_spectra.wradius",
00245                                 CPL_TYPE_INT,
00246                                 "Search radius if iterating pattern-matching "
00247                                 "with first-guess method",
00248                                 "fors.fors_detect_spectra",
00249                                 4);
00250     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00251     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00252     cpl_parameterlist_append(recipe->parameters, p);
00253 
00254     /*
00255      * Rejection threshold in dispersion relation polynomial fitting
00256      */
00257 
00258     p = cpl_parameter_new_value("fors.fors_detect_spectra.wreject",
00259                                 CPL_TYPE_DOUBLE,
00260                                 "Rejection threshold in dispersion "
00261                                 "relation fit (pixel)",
00262                                 "fors.fors_detect_spectra",
00263                                 0.7);
00264     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00265     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00266     cpl_parameterlist_append(recipe->parameters, p);
00267 
00268     /*
00269      * Line catalog table column containing the reference wavelengths
00270      */
00271 
00272     p = cpl_parameter_new_value("fors.fors_detect_spectra.wcolumn",
00273                                 CPL_TYPE_STRING,
00274                                 "Name of line catalog table column "
00275                                 "with wavelengths",
00276                                 "fors.fors_detect_spectra",
00277                                 "WLEN");
00278     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00279     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00280     cpl_parameterlist_append(recipe->parameters, p);
00281 
00282     /*
00283      * Start wavelength for spectral extraction
00284      */
00285 
00286     p = cpl_parameter_new_value("fors.fors_detect_spectra.startwavelength",
00287                                 CPL_TYPE_DOUBLE,
00288                                 "Start wavelength in spectral extraction",
00289                                 "fors.fors_detect_spectra",
00290                                 0.0);
00291     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00292     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00293     cpl_parameterlist_append(recipe->parameters, p);
00294 
00295     /*
00296      * End wavelength for spectral extraction
00297      */
00298 
00299     p = cpl_parameter_new_value("fors.fors_detect_spectra.endwavelength",
00300                                 CPL_TYPE_DOUBLE,
00301                                 "End wavelength in spectral extraction",
00302                                 "fors.fors_detect_spectra",
00303                                 0.0);
00304     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00305     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00306     cpl_parameterlist_append(recipe->parameters, p);
00307 
00308     /*
00309      * Try slit identification
00310      */
00311 
00312     p = cpl_parameter_new_value("fors.fors_detect_spectra.slit_ident",
00313                                 CPL_TYPE_BOOL,
00314                                 "Attempt slit identification for MOS or MXU",
00315                                 "fors.fors_detect_spectra",
00316                                 TRUE);
00317     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_ident");
00318     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00319     cpl_parameterlist_append(recipe->parameters, p);
00320 
00321 
00322     return 0;
00323 }
00324 
00325 
00334 static int fors_detect_spectra_exec(cpl_plugin *plugin)
00335 {
00336     cpl_recipe *recipe;
00337     
00338     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00339         recipe = (cpl_recipe *)plugin;
00340     else 
00341         return -1;
00342 
00343     return fors_detect_spectra(recipe->parameters, recipe->frames);
00344 }
00345 
00346 
00355 static int fors_detect_spectra_destroy(cpl_plugin *plugin)
00356 {
00357     cpl_recipe *recipe;
00358     
00359     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00360         recipe = (cpl_recipe *)plugin;
00361     else 
00362         return -1;
00363 
00364     cpl_parameterlist_delete(recipe->parameters); 
00365 
00366     return 0;
00367 }
00368 
00369 
00379 static int fors_detect_spectra(cpl_parameterlist *parlist, 
00380                                cpl_frameset *frameset)
00381 {
00382 
00383     const char *recipe = "fors_detect_spectra";
00384 
00385 
00386     /*
00387      * Input parameters
00388      */
00389 
00390     double      dispersion;
00391     double      peakdetection;
00392     int         wdegree;
00393     int         wradius;
00394     double      wreject;
00395     const char *wcolumn;
00396     double      startwavelength;
00397     double      endwavelength;
00398     int         slit_ident;
00399 
00400     /*
00401      * CPL objects
00402      */
00403 
00404     cpl_image        *spectra     = NULL;
00405     cpl_image        *checkwave   = NULL;
00406     cpl_image        *refimage    = NULL;
00407     cpl_mask         *refmask     = NULL;
00408     cpl_table        *grism_table = NULL;
00409     cpl_table        *wavelengths = NULL;
00410     cpl_table        *slits       = NULL;
00411     cpl_table        *positions   = NULL;
00412     cpl_table        *maskslits   = NULL;
00413     cpl_vector       *lines       = NULL;
00414     cpl_propertylist *header      = NULL;
00415 
00416     /*
00417      * Auxiliary variables
00418      */
00419 
00420     char        version[80];
00421     const char *arc_tag;
00422     const char *spectra_detection_tag;
00423     const char *slit_map_tag;
00424     const char *slit_location_tag;
00425     int         lamp_mxu;
00426     int         lamp_mos;
00427     int         lamp_lss;
00428     int         mxu, mos;
00429     int         treat_as_lss = 0;
00430     int         nslits;
00431     double     *xpos;
00432     double      mxpos;
00433     int         narc;
00434     int         nlines;
00435     int         rebin;
00436     double     *line;
00437     int         nx, ny;
00438     double      reference;
00439     int         i;
00440 
00441     char       *instrume = NULL;
00442 
00443 
00444     cpl_msg_set_indentation(2);
00445 
00446     if (dfs_files_dont_exist(frameset))
00447         fors_detect_spectra_exit(NULL);
00448 
00449     /*
00450      * Get configuration parameters
00451      */
00452 
00453     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00454     cpl_msg_indent_more();
00455     
00456     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00457         fors_detect_spectra_exit("Too many in input: GRISM_TABLE"); 
00458 
00459     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00460 
00461     dispersion = dfs_get_parameter_double(parlist,
00462                     "fors.fors_detect_spectra.dispersion", grism_table);
00463 
00464     if (dispersion <= 0.0)
00465         fors_detect_spectra_exit("Invalid spectral dispersion value");
00466 
00467     peakdetection = dfs_get_parameter_double(parlist,
00468                     "fors.fors_detect_spectra.peakdetection", grism_table);
00469     if (peakdetection <= 0.0)
00470         fors_detect_spectra_exit("Invalid peak detection level");
00471 
00472     wdegree = dfs_get_parameter_int(parlist,
00473                     "fors.fors_detect_spectra.wdegree", grism_table);
00474 
00475     if (wdegree < 1)
00476         fors_detect_spectra_exit("Invalid polynomial degree");
00477 
00478     if (wdegree > 5)
00479         fors_detect_spectra_exit("Max allowed polynomial degree is 5");
00480 
00481     wradius = dfs_get_parameter_int(parlist, 
00482                                     "fors.fors_detect_spectra.wradius", NULL);
00483 
00484     if (wradius < 0)
00485         fors_detect_spectra_exit("Invalid search radius");
00486 
00487     wreject = dfs_get_parameter_double(parlist, 
00488                                     "fors.fors_detect_spectra.wreject", NULL);
00489 
00490     if (wreject <= 0.0)
00491         fors_detect_spectra_exit("Invalid rejection threshold");
00492 
00493     wcolumn = dfs_get_parameter_string(parlist, 
00494                                     "fors.fors_detect_spectra.wcolumn", NULL);
00495 
00496     startwavelength = dfs_get_parameter_double(parlist,
00497                     "fors.fors_detect_spectra.startwavelength", grism_table);
00498     if (startwavelength > 1.0)
00499         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00500             fors_detect_spectra_exit("Invalid wavelength");
00501 
00502     endwavelength = dfs_get_parameter_double(parlist,
00503                     "fors.fors_detect_spectra.endwavelength", grism_table);
00504     if (endwavelength > 1.0) {
00505         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00506             fors_detect_spectra_exit("Invalid wavelength");
00507         if (startwavelength < 1.0)
00508             fors_detect_spectra_exit("Invalid wavelength interval");
00509     }
00510 
00511     if (startwavelength > 1.0)
00512         if (endwavelength - startwavelength <= 0.0)
00513             fors_detect_spectra_exit("Invalid wavelength interval");
00514 
00515     slit_ident = dfs_get_parameter_bool(parlist,
00516                     "fors.fors_detect_spectra.slit_ident", NULL);
00517 
00518     cpl_table_delete(grism_table); grism_table = NULL;
00519 
00520     if (cpl_error_get_code())
00521         fors_detect_spectra_exit("Failure reading the "
00522                                  "configuration parameters");
00523 
00524 
00525     cpl_msg_indent_less();
00526     cpl_msg_info(recipe, "Check input set-of-frames:");
00527     cpl_msg_indent_more();
00528 
00529     narc  = lamp_mxu = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MXU");
00530     narc += lamp_mos = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MOS");
00531     narc += lamp_lss = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_LSS");
00532 
00533     if (narc == 0) {
00534         fors_detect_spectra_exit("Missing input arc lamp frame");
00535     }
00536     if (narc > 1) {
00537         cpl_msg_error(recipe, "Too many input arc lamp frames (%d > 1)", narc);
00538         fors_detect_spectra_exit(NULL);
00539     }
00540 
00541     mxu = mos = 0;
00542 
00543     if (lamp_mxu) {
00544         mxu = 1;
00545         arc_tag               = "LAMP_UNBIAS_MXU";
00546         spectra_detection_tag = "SPECTRA_DETECTION_MXU";
00547         slit_map_tag          = "SLIT_MAP_MXU";
00548         slit_location_tag     = "SLIT_LOCATION_DETECT_MXU";
00549     }
00550     else if (lamp_mos) {
00551         mos = 1;
00552         arc_tag               = "LAMP_UNBIAS_MOS";
00553         spectra_detection_tag = "SPECTRA_DETECTION_MOS";
00554         slit_map_tag          = "SLIT_MAP_MOS";
00555         slit_location_tag     = "SLIT_LOCATION_DETECT_MOS";
00556     }
00557     else if (lamp_lss) {
00558         fors_detect_spectra_exit("Use recipe fors_wave_calib_lss "
00559                                  "for LSS data reduction");
00560     }
00561 
00562 
00563     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00564         fors_detect_spectra_exit("Missing required input: MASTER_LINECAT");
00565 
00566     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00567         fors_detect_spectra_exit("Too many in input: MASTER_LINECAT");
00568 
00569     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00570         fors_detect_spectra_exit("Input frames are not from the same grism");
00571 
00572     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00573         fors_detect_spectra_exit("Input frames are not from the same filter");
00574 
00575     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00576         fors_detect_spectra_exit("Input frames are not from the same chip");
00577 
00578 
00579     /*
00580      * Get the reference wavelength and the rebin factor along the
00581      * dispersion direction from the arc lamp exposure
00582      */
00583 
00584     header = dfs_load_header(frameset, arc_tag, 0);
00585 
00586     if (header == NULL)
00587         fors_detect_spectra_exit("Cannot load arc lamp header");
00588 
00589     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00590     if (instrume == NULL)
00591         fors_detect_spectra_exit("Missing keyword INSTRUME in arc lamp header");
00592 
00593     if (instrume[4] == '1')
00594         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00595     if (instrume[4] == '2')
00596         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00597 
00598     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00599 
00600     if (cpl_error_get_code() != CPL_ERROR_NONE)
00601         fors_detect_spectra_exit("Missing keyword ESO INS GRIS1 WLEN "
00602                                  "in arc lamp frame header");
00603 
00604     if (reference < 3000.0)   /* Perhaps in nanometers... */
00605         reference *= 10;
00606 
00607     if (reference < 3000.0 || reference > 13000.0) {
00608         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00609                       "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00610                       reference);
00611         fors_detect_spectra_exit(NULL);
00612     }
00613 
00614     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00615 
00616     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00617 
00618     if (cpl_error_get_code() != CPL_ERROR_NONE)
00619         fors_detect_spectra_exit("Missing keyword ESO DET WIN1 BINX "
00620                                  "in arc lamp frame header");
00621 
00622     if (rebin != 1) {
00623         dispersion *= rebin;
00624         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00625                         "working dispersion used is %f A/pixel", rebin,
00626                         dispersion);
00627     }
00628 
00629 
00630     cpl_msg_info(recipe, "Produce mask slit position table...");
00631 
00632     if (mos)
00633         maskslits = mos_load_slits_fors_mos(header);
00634     else
00635         maskslits = mos_load_slits_fors_mxu(header);
00636 
00637     cpl_propertylist_delete(header); header = NULL;
00638 
00639 
00640     /*
00641      * Check if all slits have the same X offset: in such case,
00642      * treat the observation as a long-slit one!
00643      */
00644 
00645     mxpos = cpl_table_get_column_median(maskslits, "xtop");
00646     xpos = cpl_table_get_data_double(maskslits, "xtop");
00647     nslits = cpl_table_get_nrow(maskslits);
00648 
00649     treat_as_lss = 1;
00650     for (i = 0; i < nslits; i++) {
00651         if (fabs(mxpos-xpos[i]) > 0.01) {
00652             treat_as_lss = 0;
00653             break;
00654         }
00655     }
00656 
00657     if (treat_as_lss) {
00658         cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00659                       "The LSS data reduction strategy must be applied: "
00660                       "please use recipe fors_wave_calib_lss", mxpos);
00661         fors_detect_spectra_exit(NULL);
00662     }
00663 
00664     if (slit_ident == 0) {
00665         cpl_table_delete(maskslits); maskslits = NULL;
00666     }
00667 
00668 
00669     cpl_msg_indent_less();
00670     cpl_msg_info(recipe, "Load arc lamp exposure...");
00671     cpl_msg_indent_more();
00672 
00673     spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00674 
00675     if (spectra == NULL)
00676         fors_detect_spectra_exit("Cannot load arc lamp exposure");
00677 
00678 
00679     cpl_msg_indent_less();
00680     cpl_msg_info(recipe, "Load input line catalog...");
00681     cpl_msg_indent_more();
00682 
00683     wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00684 
00685     if (wavelengths == NULL)
00686         fors_detect_spectra_exit("Cannot load line catalog");
00687 
00688 
00689     /*
00690      * Cast the wavelengths into a (double precision) CPL vector
00691      */
00692 
00693     nlines = cpl_table_get_nrow(wavelengths);
00694 
00695     if (nlines == 0)
00696         fors_detect_spectra_exit("Empty input line catalog");
00697 
00698     if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00699         cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00700                       wcolumn);
00701         fors_detect_spectra_exit(NULL);
00702     }
00703 
00704     line = cpl_malloc(nlines * sizeof(double));
00705 
00706     for (i = 0; i < nlines; i++)
00707         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00708 
00709     cpl_table_delete(wavelengths); wavelengths = NULL;
00710 
00711     lines = cpl_vector_wrap(nlines, line);
00712 
00713 
00714     cpl_msg_indent_less();
00715     cpl_msg_info(recipe, "Detecting spectra on CCD...");
00716     cpl_msg_indent_more();
00717 
00718     nx = cpl_image_get_size_x(spectra);
00719     ny = cpl_image_get_size_y(spectra);
00720 
00721     refmask = cpl_mask_new(nx, ny);
00722 
00723     if (mos_saturation_process(spectra))
00724     fors_detect_spectra_exit("Cannot process saturation");
00725 
00726     if (mos_subtract_background(spectra))
00727     fors_detect_spectra_exit("Cannot subtract the background");
00728 
00729     checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion,
00730                                                peakdetection, wradius,
00731                                                wdegree, wreject, reference,
00732                                                &startwavelength, &endwavelength,
00733                                                NULL, NULL, NULL, NULL, NULL,
00734                                                NULL, refmask);
00735 
00736     cpl_image_delete(spectra); spectra = NULL;
00737     cpl_vector_delete(lines); lines = NULL;
00738 
00739     if (checkwave == NULL)
00740         fors_detect_spectra_exit("Wavelength calibration failure.");
00741 
00742 
00743     /*
00744      * Save check image to disk
00745      */
00746 
00747     header = cpl_propertylist_new();
00748     cpl_propertylist_update_double(header, "CRPIX1", 1.0);
00749     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
00750     cpl_propertylist_update_double(header, "CRVAL1",
00751                                    startwavelength + dispersion/2);
00752     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
00753     /* cpl_propertylist_update_double(header, "CDELT1", dispersion);
00754     cpl_propertylist_update_double(header, "CDELT2", 1.0); */
00755     cpl_propertylist_update_double(header, "CD1_1", dispersion);
00756     cpl_propertylist_update_double(header, "CD1_2", 0.0);
00757     cpl_propertylist_update_double(header, "CD2_1", 0.0);
00758     cpl_propertylist_update_double(header, "CD2_2", 1.0);
00759     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
00760     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
00761 
00762     if (dfs_save_image(frameset, checkwave, spectra_detection_tag, header,
00763                        parlist, recipe, version))
00764         fors_detect_spectra_exit(NULL);
00765 
00766     cpl_image_delete(checkwave); checkwave = NULL;
00767     cpl_propertylist_delete(header); header = NULL;
00768 
00769 
00770     cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD...");
00771     slits = mos_locate_spectra(refmask);
00772 
00773     if (!slits) {
00774         cpl_msg_error(cpl_error_get_where(), cpl_error_get_message());
00775         fors_detect_spectra_exit("No slits could be detected!");
00776     }
00777 
00778     refimage = cpl_image_new_from_mask(refmask);
00779     cpl_mask_delete(refmask); refmask = NULL;
00780 
00781     header = dfs_load_header(frameset, arc_tag, 0);
00782     if (dfs_save_image(frameset, refimage, slit_map_tag, header,
00783                        parlist, recipe, version))
00784         fors_detect_spectra_exit(NULL);
00785     cpl_propertylist_delete(header); header = NULL;
00786 
00787     cpl_image_delete(refimage); refimage = NULL;
00788 
00789     if (slit_ident) {
00790 
00791         /*
00792          * Attempt slit identification: this recipe may continue even
00793          * in case of failed identification (i.e., the position table is
00794          * not produced, but an error is not set). In case of failure,
00795          * the spectra would be still extracted, even if they would not
00796          * be associated to slits on the mask.
00797          *
00798          * The reason for making the slit identification an user option
00799          * (via the parameter slit_ident) is to offer the possibility
00800          * to avoid identifications that are only apparently successful,
00801          * as it would happen in the case of an incorrect slit description
00802          * in the data header.
00803          */
00804 
00805         cpl_msg_indent_less();
00806         cpl_msg_info(recipe, "Attempt slit identification (optional)...");
00807         cpl_msg_indent_more();
00808 
00809         positions = mos_identify_slits(slits, maskslits, NULL);
00810         cpl_table_delete(maskslits); maskslits = NULL;
00811 
00812         if (positions) {
00813             cpl_table_delete(slits);
00814             slits = positions;
00815 
00816             /*
00817              * Eliminate slits which are _entirely_ outside the CCD
00818              */
00819 
00820             cpl_table_and_selected_double(slits,
00821                                           "ybottom", CPL_GREATER_THAN, ny-1);
00822             cpl_table_or_selected_double(slits,
00823                                           "ytop", CPL_LESS_THAN, 0);
00824             cpl_table_erase_selected(slits);
00825 
00826             nslits = cpl_table_get_nrow(slits);
00827 
00828             if (nslits == 0)
00829                 fors_detect_spectra_exit("No slits found on the CCD");
00830 
00831             cpl_msg_info(recipe, "%d slits are entirely or partially "
00832                          "contained in CCD", nslits);
00833 
00834         }
00835         else {
00836             slit_ident = 0;
00837             cpl_msg_info(recipe, "Global distortion model cannot be computed");
00838             if (cpl_error_get_code() != CPL_ERROR_NONE) {
00839                 fors_detect_spectra_exit(NULL);
00840             }
00841         }
00842     }
00843 
00844     if (dfs_save_table(frameset, slits, slit_location_tag, NULL,
00845                        parlist, recipe, version))
00846         fors_detect_spectra_exit(NULL);
00847 
00848     cpl_table_delete(slits); slits = NULL;
00849 
00850     return 0;
00851 }

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