FORS Pipeline Reference Manual 4.9.20
fors_extract_slits.c
00001 /* $Id: fors_extract_slits.c,v 1.6 2013/02/28 15:13:48 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2013/02/28 15:13:48 $
00024  * $Revision: 1.6 $
00025  * $Name: fors-4_9_20 $
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_extract_slits_create(cpl_plugin *);
00038 static int fors_extract_slits_exec(cpl_plugin *);
00039 static int fors_extract_slits_destroy(cpl_plugin *);
00040 static int fors_extract_slits(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char fors_extract_slits_description[] =
00043 "This recipe is used to extract MOS/MXU slit spectra, following their\n"
00044 "curvature, and to remap them into a spatially rectified image.\n"
00045 "Please refer to the FORS Pipeline User's Manual for details about\n"
00046 "the spectra remapping technique. Note however that the interpolation\n"
00047 "is done exclusively along the spatial direction, and therefore the\n"
00048 "output rectified image will have the same x size of the input spectral\n" 
00049 "image.\n"
00050 "\n"
00051 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00052 "Input files:\n\n"
00053 "  DO category:               Type:       Explanation:         Required:\n"
00054 "  LAMP_UNBIAS_MXU\n"
00055 "  or SCIENCE_UNBIAS_MXU\n"
00056 "  or SCIENCE_UNFLAT_MXU\n"
00057 "  or STANDARD_UNBIAS_MXU\n"
00058 "  or STANDARD_UNFLAT_MXU\n"
00059 "  or UNMAPPED_SCI_MXU\n"
00060 "  or UNMAPPED_STD_MXU\n"
00061 "  or UNMAPPED_SKY_SCI_MXU\n"
00062 "  or UNMAPPED_SKY_STD_MXU    Calib       Spectral frame          Y\n"
00063 "  SLIT_LOCATION_DETECT_MXU\n"
00064 "  or SLIT_LOCATION_MXU       Calib       Master flat frame       Y\n"
00065 "  CURV_COEFF_MXU             Calib       Spectral curvature      Y\n"
00066 "  GRISM_TABLE                Calib       Grism table             .\n\n"
00067 "Output files:\n\n"
00068 "  DO category:               Data type:  Explanation:\n"
00069 "  RECTIFIED_LAMP_MXU\n"
00070 "  or RECTIFIED_ALL_SCI_MXU\n"
00071 "  or RECTIFIED_ALL_STD_MXU\n"
00072 "  or RECTIFIED_SCI_MXU\n"
00073 "  or RECTIFIED_STD_MXU\n"
00074 "  or RECTIFIED_SKY_SCI_MXU\n"
00075 "  or RECTIFIED_SKY_STD_MXU   FITS image  Rectified slit spectra\n\n";
00076 
00077 #define fors_extract_slits_exit(message)      \
00078 {                                             \
00079 if (message) cpl_msg_error(recipe, message);  \
00080 cpl_image_delete(spectra);                    \
00081 cpl_image_delete(spatial);                    \
00082 cpl_table_delete(grism_table);                \
00083 cpl_table_delete(maskslits);                  \
00084 cpl_table_delete(slits);                      \
00085 cpl_table_delete(polytraces);                 \
00086 cpl_propertylist_delete(header);              \
00087 cpl_msg_indent_less();                        \
00088 return -1;                                    \
00089 }
00090 
00091 #define fors_extract_slits_exit_memcheck(message)  \
00092 {                                               \
00093 if (message) cpl_msg_info(recipe, message);     \
00094 printf("free spectra (%p)\n", spectra);         \
00095 cpl_image_delete(spectra);                      \
00096 printf("free spatial (%p)\n", spatial);         \
00097 cpl_image_delete(spatial);                      \
00098 printf("free grism_table (%p)\n", grism_table); \
00099 cpl_table_delete(grism_table);                  \
00100 printf("free maskslits (%p)\n", maskslits);     \
00101 cpl_table_delete(maskslits);                    \
00102 printf("free slits (%p)\n", slits);             \
00103 cpl_table_delete(slits);                        \
00104 printf("free polytraces (%p)\n", polytraces);   \
00105 cpl_table_delete(polytraces);                   \
00106 printf("free header (%p)\n", header);           \
00107 cpl_propertylist_delete(header);                \
00108 cpl_msg_indent_less();                          \
00109 return 0;                                       \
00110 }
00111 
00112 
00124 int cpl_plugin_get_info(cpl_pluginlist *list)
00125 {
00126     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00127     cpl_plugin *plugin = &recipe->interface;
00128 
00129     cpl_plugin_init(plugin,
00130                     CPL_PLUGIN_API,
00131                     FORS_BINARY_VERSION,
00132                     CPL_PLUGIN_TYPE_RECIPE,
00133                     "fors_extract_slits",
00134                     "Spatial rectification of spectral image",
00135                     fors_extract_slits_description,
00136                     "Carlo Izzo",
00137                     PACKAGE_BUGREPORT,
00138     "This file is currently part of the FORS Instrument Pipeline\n"
00139     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00140     "This program is free software; you can redistribute it and/or modify\n"
00141     "it under the terms of the GNU General Public License as published by\n"
00142     "the Free Software Foundation; either version 2 of the License, or\n"
00143     "(at your option) any later version.\n\n"
00144     "This program is distributed in the hope that it will be useful,\n"
00145     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00146     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00147     "GNU General Public License for more details.\n\n"
00148     "You should have received a copy of the GNU General Public License\n"
00149     "along with this program; if not, write to the Free Software Foundation,\n"
00150     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00151                     fors_extract_slits_create,
00152                     fors_extract_slits_exec,
00153                     fors_extract_slits_destroy);
00154 
00155     cpl_pluginlist_append(list, plugin);
00156     
00157     return 0;
00158 }
00159 
00160 
00171 static int fors_extract_slits_create(cpl_plugin *plugin)
00172 {
00173     cpl_recipe    *recipe;
00174     cpl_parameter *p;
00175 
00176     /* 
00177      * Check that the plugin is part of a valid recipe 
00178      */
00179 
00180     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00181         recipe = (cpl_recipe *)plugin;
00182     else 
00183         return -1;
00184 
00185     /* 
00186      * Create the (empty) parameters list in the cpl_recipe object 
00187      */
00188 
00189     recipe->parameters = cpl_parameterlist_new(); 
00190 
00191     /*
00192      * Dispersion
00193      */
00194 
00195     p = cpl_parameter_new_value("fors.fors_extract_slits.dispersion",
00196                                 CPL_TYPE_DOUBLE,
00197                                 "Expected spectral dispersion (Angstrom/pixel)",
00198                                 "fors.fors_extract_slits",
00199                                 0.0);
00200     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00201     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00202     cpl_parameterlist_append(recipe->parameters, p);
00203 
00204     /*
00205      * Start wavelength for spectral extraction
00206      */
00207 
00208     p = cpl_parameter_new_value("fors.fors_extract_slits.startwavelength",
00209                                 CPL_TYPE_DOUBLE,
00210                                 "Start wavelength in spectral extraction",
00211                                 "fors.fors_extract_slits",
00212                                 0.0);
00213     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00214     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00215     cpl_parameterlist_append(recipe->parameters, p);
00216 
00217     /*
00218      * End wavelength for spectral extraction
00219      */
00220 
00221     p = cpl_parameter_new_value("fors.fors_extract_slits.endwavelength",
00222                                 CPL_TYPE_DOUBLE,
00223                                 "End wavelength in spectral extraction",
00224                                 "fors.fors_extract_slits",
00225                                 0.0);
00226     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00227     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00228     cpl_parameterlist_append(recipe->parameters, p);
00229 
00230     /*
00231      * Flux conservation
00232      */
00233  
00234     p = cpl_parameter_new_value("fors.fors_extract_slits.flux",
00235                                 CPL_TYPE_BOOL,
00236                                 "Apply flux conservation",
00237                                 "fors.fors_extract_slits",
00238                                 TRUE);
00239     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00240     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00241     cpl_parameterlist_append(recipe->parameters, p);
00242 
00243     return 0;
00244 }
00245 
00246 
00255 static int fors_extract_slits_exec(cpl_plugin *plugin)
00256 {
00257     cpl_recipe *recipe;
00258     
00259     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00260         recipe = (cpl_recipe *)plugin;
00261     else 
00262         return -1;
00263 
00264     return fors_extract_slits(recipe->parameters, recipe->frames);
00265 }
00266 
00267 
00276 static int fors_extract_slits_destroy(cpl_plugin *plugin)
00277 {
00278     cpl_recipe *recipe;
00279     
00280     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00281         recipe = (cpl_recipe *)plugin;
00282     else 
00283         return -1;
00284 
00285     cpl_parameterlist_delete(recipe->parameters); 
00286 
00287     return 0;
00288 }
00289 
00290 
00300 static int fors_extract_slits(cpl_parameterlist *parlist, 
00301                                cpl_frameset *frameset)
00302 {
00303 
00304     const char *recipe = "fors_extract_slits";
00305 
00306 
00307     /*
00308      * Input parameters
00309      */
00310 
00311     double      dispersion;
00312     double      startwavelength;
00313     double      endwavelength;
00314     int         flux;
00315 
00316     /*
00317      * CPL objects
00318      */
00319 
00320     cpl_image        *spectra     = NULL;
00321     cpl_image        *spatial     = NULL;
00322     cpl_table        *grism_table = NULL;
00323     cpl_table        *slits       = NULL;
00324     cpl_table        *polytraces  = NULL;
00325     cpl_table        *maskslits   = NULL;
00326     cpl_propertylist *header      = NULL;
00327 
00328     /*
00329      * Auxiliary variables
00330      */
00331 
00332     char        version[80];
00333     const char *input_tag;
00334     const char *output_tag;
00335     const char *slit_location_tag;
00336     const char *curv_coeff_tag;
00337     int         nframes;
00338     int         rebin;
00339     int         nslits;
00340     int         treat_as_lss;
00341     int         i;
00342     double      reference;
00343     double     *xpos;
00344     double      mxpos;
00345     int         mxu, mos, lss;
00346     int         slit_l, slit_d;
00347     int         lamp_mxu;
00348     int         lamp_mos;
00349     int         lamp_lss;
00350     int         scib_mxu;
00351     int         scib_mos;
00352     int         scib_lss;
00353     int         scif_mxu;
00354     int         scif_mos;
00355     int         scif_lss;
00356     int         stab_mxu;
00357     int         stab_mos;
00358     int         stab_lss;
00359     int         staf_mxu;
00360     int         staf_mos;
00361     int         staf_lss;
00362     int         sciu_mxu;
00363     int         sciu_mos;
00364     int         sciu_lss;
00365     int         stau_mxu;
00366     int         stau_mos;
00367     int         stau_lss;
00368     int         scis_mxu;
00369     int         scis_mos;
00370     int         scis_lss;
00371     int         stas_mxu;
00372     int         stas_mos;
00373     int         stas_lss;
00374     int         nslits_out_det = 0;
00375 
00376     char       *instrume = NULL;
00377 
00378 
00379     cpl_msg_set_indentation(2);
00380 
00381     if (dfs_files_dont_exist(frameset))
00382         fors_extract_slits_exit(NULL);
00383 
00384 
00385     /*
00386      * Get configuration parameters
00387      */
00388 
00389     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00390     cpl_msg_indent_more();
00391     
00392     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00393         fors_extract_slits_exit("Too many in input: GRISM_TABLE"); 
00394 
00395     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00396 
00397     dispersion = dfs_get_parameter_double(parlist,
00398                     "fors.fors_extract_slits.dispersion", grism_table);
00399 
00400     if (dispersion <= 0.0)
00401         fors_extract_slits_exit("Invalid spectral dispersion value");
00402 
00403     startwavelength = dfs_get_parameter_double(parlist,
00404                     "fors.fors_extract_slits.startwavelength", grism_table);
00405     if (startwavelength > 1.0)
00406         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00407             fors_extract_slits_exit("Invalid wavelength");
00408 
00409     endwavelength = dfs_get_parameter_double(parlist,
00410                     "fors.fors_extract_slits.endwavelength", grism_table);
00411     if (endwavelength > 1.0) {
00412         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00413             fors_extract_slits_exit("Invalid wavelength");
00414         if (startwavelength < 1.0)
00415             fors_extract_slits_exit("Invalid wavelength interval");
00416     }
00417 
00418     if (startwavelength > 1.0)
00419         if (endwavelength - startwavelength <= 0.0)
00420             fors_extract_slits_exit("Invalid wavelength interval");
00421 
00422     flux = dfs_get_parameter_bool(parlist, 
00423                                   "fors.fors_extract_slits.flux", NULL);
00424 
00425     cpl_table_delete(grism_table); grism_table = NULL;
00426 
00427     if (cpl_error_get_code())
00428         fors_extract_slits_exit("Failure reading the configuration parameters");
00429 
00430 
00431     cpl_msg_indent_less();
00432     cpl_msg_info(recipe, "Check input set-of-frames:");
00433     cpl_msg_indent_more();
00434 
00435     mxu  = lamp_mxu = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MXU");
00436     mos  = lamp_mos = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_MOS");
00437     lss  = lamp_lss = cpl_frameset_count_tags(frameset, "LAMP_UNBIAS_LSS");
00438     mxu += scib_mxu = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_MXU");
00439     mos += scib_mos = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_MOS");
00440     lss += scib_lss = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_LSS");
00441     mxu += scif_mxu = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_MXU");
00442     mos += scif_mos = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_MOS");
00443     lss += scif_lss = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_LSS");
00444     mxu += stab_mxu = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_MXU");
00445     mos += stab_mos = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_MOS");
00446     lss += stab_lss = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_LSS");
00447     mxu += staf_mxu = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_MXU");
00448     mos += staf_mos = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_MOS");
00449     lss += staf_lss = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_LSS");
00450     mxu += sciu_mxu = cpl_frameset_count_tags(frameset, "UNMAPPED_SCI_MXU");
00451     mos += sciu_mos = cpl_frameset_count_tags(frameset, "UNMAPPED_SCI_MOS");
00452     lss += sciu_lss = cpl_frameset_count_tags(frameset, "UNMAPPED_SCI_LSS");
00453     mxu += stau_mxu = cpl_frameset_count_tags(frameset, "UNMAPPED_STD_MXU");
00454     mos += stau_mos = cpl_frameset_count_tags(frameset, "UNMAPPED_STD_MOS");
00455     lss += stau_lss = cpl_frameset_count_tags(frameset, "UNMAPPED_STD_LSS");
00456     mxu += scis_mxu = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_SCI_MXU");
00457     mos += scis_mos = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_SCI_MOS");
00458     lss += scis_lss = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_SCI_LSS");
00459     mxu += stas_mxu = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_STD_MXU");
00460     mos += stas_mos = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_STD_MOS");
00461     lss += stas_lss = cpl_frameset_count_tags(frameset, "UNMAPPED_SKY_STD_LSS");
00462 
00463     nframes = mos + mxu + lss;
00464 
00465     if (nframes == 0) {
00466         fors_extract_slits_exit("Missing input spectral frame");
00467     }
00468     if (nframes > 1) {
00469         cpl_msg_error(recipe, 
00470                       "Too many input spectral frames (%d > 1)", nframes);
00471         fors_extract_slits_exit(NULL);
00472     }
00473 
00474     if (lss)
00475         fors_extract_slits_exit("Use this recipe just with MOS/MXU data.");
00476 
00477     if (mxu) {
00478         slit_l = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_MXU");
00479         slit_d = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_DETECT_MXU");
00480     }
00481     else {
00482         slit_l = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_MOS");
00483         slit_d = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_DETECT_MOS");
00484     }
00485 
00486     nframes = slit_l + slit_d;
00487 
00488     if (nframes == 0) {
00489         fors_extract_slits_exit("Missing input slit location table");
00490     }
00491     if (nframes > 1) {
00492         cpl_msg_error(recipe,
00493                       "Too many input slit location tables (%d > 1)", nframes);
00494         fors_extract_slits_exit(NULL);
00495     }
00496 
00497     if (slit_l) {
00498         if (mxu)
00499             slit_location_tag = "SLIT_LOCATION_MXU";
00500         else
00501             slit_location_tag = "SLIT_LOCATION_MOS";
00502     }
00503     else {
00504         if (mxu)
00505             slit_location_tag = "SLIT_LOCATION_DETECT_MXU";
00506         else
00507             slit_location_tag = "SLIT_LOCATION_DETECT_MOS";
00508     }
00509 
00510     if (mxu)
00511         curv_coeff_tag = "CURV_COEFF_MXU";
00512     else
00513         curv_coeff_tag = "CURV_COEFF_MOS";
00514 
00515     if (lamp_mxu) {
00516         input_tag = "LAMP_UNBIAS_MXU";
00517         output_tag = "RECTIFIED_LAMP_MXU";
00518     }
00519     else if (lamp_mos) {
00520         input_tag = "LAMP_UNBIAS_MOS";
00521         output_tag = "RECTIFIED_LAMP_MOS";
00522     }
00523     else if (scib_mxu) {
00524         input_tag = "SCIENCE_UNBIAS_MXU";
00525         output_tag = "RECTIFIED_ALL_SCI_MXU";
00526     }
00527     else if (scib_mos) {
00528         input_tag = "SCIENCE_UNBIAS_MOS";
00529         output_tag = "RECTIFIED_ALL_SCI_MOS";
00530     }
00531     else if (scif_mxu) {
00532         input_tag = "SCIENCE_UNFLAT_MXU";
00533         output_tag = "RECTIFIED_ALL_SCI_MXU";
00534     }
00535     else if (scif_mos) {
00536         input_tag = "SCIENCE_UNFLAT_MOS";
00537         output_tag = "RECTIFIED_ALL_SCI_MOS";
00538     }
00539     else if (stab_mxu) {
00540         input_tag = "STANDARD_UNBIAS_MXU";
00541         output_tag = "RECTIFIED_ALL_STD_MXU";
00542     }
00543     else if (stab_mos) {
00544         input_tag = "STANDARD_UNBIAS_MOS";
00545         output_tag = "RECTIFIED_ALL_STD_MOS";
00546     }
00547     else if (staf_mxu) {
00548         input_tag = "STANDARD_UNFLAT_MXU";
00549         output_tag = "RECTIFIED_ALL_STD_MXU";
00550     }
00551     else if (staf_mos) {
00552         input_tag = "STANDARD_UNFLAT_MOS";
00553         output_tag = "RECTIFIED_ALL_STD_MOS";
00554     }
00555     else if (sciu_mxu) {
00556         input_tag = "UNMAPPED_SCI_MXU";
00557         output_tag = "RECTIFIED_SCI_MXU";
00558     }
00559     else if (sciu_mos) {
00560         input_tag = "UNMAPPED_SCI_MOS";
00561         output_tag = "RECTIFIED_SCI_MOS";
00562     }
00563     else if (stau_mxu) {
00564         input_tag = "UNMAPPED_STD_MXU";
00565         output_tag = "RECTIFIED_STD_MXU";
00566     }
00567     else if (stau_mos) {
00568         input_tag = "UNMAPPED_STD_MOS";
00569         output_tag = "RECTIFIED_STD_MOS";
00570     }
00571     else if (scis_mxu) {
00572         input_tag = "UNMAPPED_SKY_SCI_MXU";
00573         output_tag = "RECTIFIED_SKY_SCI_MXU";
00574     }
00575     else if (scis_mos) {
00576         input_tag = "UNMAPPED_SKY_SCI_MOS";
00577         output_tag = "RECTIFIED_SKY_SCI_MOS";
00578     }
00579     else if (stas_mxu) {
00580         input_tag = "UNMAPPED_SKY_STD_MXU";
00581         output_tag = "RECTIFIED_SKY_STD_MXU";
00582     }
00583     else if (stas_mos) {
00584         input_tag = "UNMAPPED_SKY_STD_MOS";
00585         output_tag = "RECTIFIED_SKY_STD_MOS";
00586     }
00587 
00588     header = dfs_load_header(frameset, input_tag, 0);
00589 
00590     if (header == NULL)
00591         fors_extract_slits_exit("Cannot load master flat frame header");
00592 
00593     if (mos)
00594         maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00595     else
00596         maskslits = mos_load_slits_fors_mxu(header);
00597 
00598     /*
00599      * Check if all slits have the same X offset: in such case, abort!
00600      */
00601 
00602     treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
00603 
00604     cpl_table_delete(maskslits); maskslits = NULL;
00605 
00606     if (treat_as_lss) {
00607         cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00608                       "The LSS data reduction strategy must be applied.", 
00609                       mxpos);
00610         fors_extract_slits_exit(NULL);
00611     }
00612 
00613     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00614         fors_extract_slits_exit("Input frames are not from the same grism");
00615 
00616     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00617         fors_extract_slits_exit("Input frames are not from the same filter");
00618 
00619     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00620         fors_extract_slits_exit("Input frames are not from the same chip");
00621 
00622 
00623     /*
00624      * Get the reference wavelength and the rebin factor along the
00625      * dispersion direction from the master flat frame
00626      */
00627 
00628     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00629     if (instrume == NULL)
00630         fors_extract_slits_exit("Missing keyword INSTRUME in master "
00631                                  "flat header");
00632 
00633     if (instrume[4] == '1')
00634         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00635     if (instrume[4] == '2')
00636         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00637 
00638     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00639 
00640     if (cpl_error_get_code() != CPL_ERROR_NONE)
00641         fors_extract_slits_exit("Missing keyword ESO INS GRIS1 WLEN "
00642                                  "in master flat frame header");
00643 
00644     if (reference < 3000.0)   /* Perhaps in nanometers... */
00645         reference *= 10;
00646 
00647     if (reference < 3000.0 || reference > 13000.0) {
00648         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00649                       "keyword ESO INS GRIS1 WLEN in master flat header",
00650                       reference);
00651         fors_extract_slits_exit(NULL);
00652     }
00653 
00654     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00655 
00656     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00657 
00658     if (cpl_error_get_code() != CPL_ERROR_NONE)
00659         fors_extract_slits_exit("Missing keyword ESO DET WIN1 BINX "
00660                                  "in master flat header");
00661 
00662     if (rebin != 1) {
00663         dispersion *= rebin;
00664         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00665                         "working dispersion used is %f A/pixel", rebin,
00666                         dispersion);
00667     }
00668 
00669     cpl_msg_indent_less();
00670     cpl_msg_info(recipe, "Load input frames...");
00671     cpl_msg_indent_more();
00672 
00673     spectra = dfs_load_image(frameset, input_tag, CPL_TYPE_FLOAT, 0, 0);
00674     if (spectra == NULL)
00675         fors_extract_slits_exit("Cannot load input spectral frame");
00676 
00677     slits = dfs_load_table(frameset, slit_location_tag, 1);
00678     if (slits == NULL)
00679         fors_extract_slits_exit("Cannot load slits location table");
00680 
00681     polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00682     if (slits == NULL)
00683         fors_extract_slits_exit("Cannot load spectral curvature table");
00684 
00685     spatial = mos_spatial_calibration(spectra, slits, polytraces, reference,
00686                                       startwavelength, endwavelength,
00687                                       dispersion, flux, NULL);
00688 
00689     cpl_image_delete(spectra); spectra = NULL;
00690     cpl_table_delete(polytraces); polytraces = NULL;
00691     cpl_table_delete(slits); slits = NULL;
00692 
00693     cpl_propertylist_delete(header); header = NULL;
00694     header = cpl_propertylist_new();
00695 
00696     cpl_propertylist_update_double(header, "CRPIX2", 1.0);
00697     cpl_propertylist_update_double(header, "CRVAL2", 1.0);
00698     /* cpl_propertylist_update_double(header, "CDELT2", 1.0); */
00699     cpl_propertylist_update_double(header, "CD1_1", 1.0);
00700     cpl_propertylist_update_double(header, "CD1_2", 0.0);
00701     cpl_propertylist_update_double(header, "CD2_1", 0.0);
00702     cpl_propertylist_update_double(header, "CD2_2", 1.0);
00703     cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
00704     cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
00705 
00706     if (dfs_save_image(frameset, spatial, output_tag,
00707                        header, parlist, recipe, version))
00708         fors_extract_slits_exit(NULL);
00709 
00710     cpl_image_delete(spatial); spatial = NULL;
00711     cpl_propertylist_delete(header); header = NULL;
00712 
00713     return 0;
00714 }