FORS Pipeline Reference Manual 4.9.20
fors_align_sky.c
00001 /* $Id: fors_align_sky.c,v 1.6 2013/02/28 15:13:15 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:15 $
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_align_sky_create(cpl_plugin *);
00038 static int fors_align_sky_exec(cpl_plugin *);
00039 static int fors_align_sky_destroy(cpl_plugin *);
00040 static int fors_align_sky(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char fors_align_sky_description[] =
00043 "This recipe is used to align the wavelength solution based on the arc\n"
00044 "lamp exposure on a set of sky lines observed on a scientific exposure.\n"
00045 "The input rectified frames are produced by the recipe fors_extract_slits.\n"
00046 "An input catalog of sky lines can be specified, otherwise an internal one\n"
00047 "is used.\n"
00048 "\n"
00049 "This recipe should be applied to multi-slit MOS/MXU data: for LSS or\n"
00050 "long-slit like data (MOS/MXU with all slits at the same offset) use recipe\n"
00051 "fors_align_sky_lss instead. Please refer to the FORS Pipeline User's Manual\n"
00052 "for more details.\n"
00053 "\n"
00054 "In the table below the MXU acronym can be alternatively read as MOS, and\n"
00055 "SCI as STD.\n\n"
00056 "Input files:\n\n"
00057 "  DO category:               Type:       Explanation:         Required:\n"
00058 "  RECTIFIED_ALL_SCI_MXU\n"
00059 "  or RECTIFIED_SKY_SCI_MXU   Calib       Frame with sky lines    Y\n"
00060 "  SPATIAL_MAP_MXU            Calib       Spatial coordinate map  Y\n"
00061 "  CURV_COEFF_MXU             Calib       Spectral curvature      Y\n"
00062 "  SLIT_LOCATION_MXU          Calib       Slit location on CCD    Y\n"
00063 "  DISP_COEFF_MXU             Calib       Dispersion solution     Y\n"
00064 "  MASTER_SKYLINECAT          Calib       Catalog of sky lines    .\n"
00065 "  GRISM_TABLE                Calib       Grism table             .\n\n"
00066 "Output files:\n\n"
00067 "  DO category:               Data type:  Explanation:\n"
00068 "  SKY_SHIFTS_SLIT_SCI_MXU    FITS table  Observed sky lines offsets\n"
00069 "  WAVELENGTH_MAP_SCI_MXU     FITS image  Wavelength mapped on CCD\n"
00070 "  DISP_COEFF_SCI_MXU         FITS image  Upgraded dispersion solution\n\n";
00071 
00072 #define fors_align_sky_exit(message)          \
00073 {                                             \
00074 if (message) cpl_msg_error(recipe, message);  \
00075 cpl_image_delete(wavemap);                    \
00076 cpl_image_delete(coordinate);                 \
00077 cpl_image_delete(rainbow);                    \
00078 cpl_image_delete(smapped);                    \
00079 cpl_table_delete(grism_table);                \
00080 cpl_table_delete(maskslits);                  \
00081 cpl_table_delete(wavelengths);                \
00082 cpl_table_delete(offsets);                    \
00083 cpl_table_delete(slits);                      \
00084 cpl_table_delete(polytraces);                 \
00085 cpl_table_delete(idscoeff);                   \
00086 cpl_vector_delete(lines);                     \
00087 cpl_propertylist_delete(header);              \
00088 cpl_msg_indent_less();                        \
00089 return -1;                                    \
00090 }
00091 
00092 #define fors_align_sky_exit_memcheck(message)   \
00093 {                                               \
00094 if (message) cpl_msg_info(recipe, message);     \
00095 printf("free wavemap (%p)\n", wavemap);         \
00096 cpl_image_delete(wavemap);                      \
00097 printf("free coordinate (%p)\n", coordinate);   \
00098 cpl_image_delete(coordinate);                   \
00099 printf("free rainbow (%p)\n", rainbow);         \
00100 cpl_image_delete(rainbow);                      \
00101 printf("free smapped (%p)\n", smapped);         \
00102 cpl_image_delete(smapped);                      \
00103 printf("free grism_table (%p)\n", grism_table); \
00104 cpl_table_delete(grism_table);                  \
00105 printf("free maskslits (%p)\n", maskslits);     \
00106 cpl_table_delete(maskslits);                    \
00107 printf("free wavelengths (%p)\n", wavelengths); \
00108 cpl_table_delete(wavelengths);                  \
00109 printf("free offsets (%p)\n", offsets);         \
00110 cpl_table_delete(offsets);                      \
00111 printf("free idscoeff (%p)\n", idscoeff);       \
00112 cpl_table_delete(idscoeff);                     \
00113 printf("free slits (%p)\n", slits);             \
00114 cpl_table_delete(slits);                        \
00115 printf("free polytraces (%p)\n", polytraces);   \
00116 cpl_table_delete(polytraces);                   \
00117 printf("free lines (%p)\n", lines);             \
00118 cpl_vector_delete(lines);                       \
00119 printf("free header (%p)\n", header);           \
00120 cpl_propertylist_delete(header);                \
00121 cpl_msg_indent_less();                          \
00122 return 0;                                       \
00123 }
00124 
00125 
00137 int cpl_plugin_get_info(cpl_pluginlist *list)
00138 {
00139     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00140     cpl_plugin *plugin = &recipe->interface;
00141 
00142     cpl_plugin_init(plugin,
00143                     CPL_PLUGIN_API,
00144                     FORS_BINARY_VERSION,
00145                     CPL_PLUGIN_TYPE_RECIPE,
00146                     "fors_align_sky",
00147                     "Upgrade wavelength solution using sky lines",
00148                     fors_align_sky_description,
00149                     "Carlo Izzo",
00150                     PACKAGE_BUGREPORT,
00151     "This file is currently part of the FORS Instrument Pipeline\n"
00152     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00153     "This program is free software; you can redistribute it and/or modify\n"
00154     "it under the terms of the GNU General Public License as published by\n"
00155     "the Free Software Foundation; either version 2 of the License, or\n"
00156     "(at your option) any later version.\n\n"
00157     "This program is distributed in the hope that it will be useful,\n"
00158     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00159     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00160     "GNU General Public License for more details.\n\n"
00161     "You should have received a copy of the GNU General Public License\n"
00162     "along with this program; if not, write to the Free Software Foundation,\n"
00163     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00164                     fors_align_sky_create,
00165                     fors_align_sky_exec,
00166                     fors_align_sky_destroy);
00167 
00168     cpl_pluginlist_append(list, plugin);
00169     
00170     return 0;
00171 }
00172 
00173 
00184 static int fors_align_sky_create(cpl_plugin *plugin)
00185 {
00186     cpl_recipe    *recipe;
00187     cpl_parameter *p;
00188 
00189     /* 
00190      * Check that the plugin is part of a valid recipe 
00191      */
00192 
00193     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00194         recipe = (cpl_recipe *)plugin;
00195     else 
00196         return -1;
00197 
00198     /* 
00199      * Create the (empty) parameters list in the cpl_recipe object 
00200      */
00201 
00202     recipe->parameters = cpl_parameterlist_new(); 
00203 
00204     /*
00205      * Dispersion
00206      */
00207 
00208     p = cpl_parameter_new_value("fors.fors_align_sky.dispersion",
00209                                 CPL_TYPE_DOUBLE,
00210                                 "Expected spectral dispersion (Angstrom/pixel)",
00211                                 "fors.fors_align_sky",
00212                                 0.0);
00213     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00214     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00215     cpl_parameterlist_append(recipe->parameters, p);
00216 
00217     /*
00218      * Start wavelength for spectral extraction
00219      */
00220 
00221     p = cpl_parameter_new_value("fors.fors_align_sky.startwavelength",
00222                                 CPL_TYPE_DOUBLE,
00223                                 "Start wavelength in spectral extraction",
00224                                 "fors.fors_align_sky",
00225                                 0.0);
00226     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00227     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00228     cpl_parameterlist_append(recipe->parameters, p);
00229 
00230     /*
00231      * End wavelength for spectral extraction
00232      */
00233 
00234     p = cpl_parameter_new_value("fors.fors_align_sky.endwavelength",
00235                                 CPL_TYPE_DOUBLE,
00236                                 "End wavelength in spectral extraction",
00237                                 "fors.fors_align_sky",
00238                                 0.0);
00239     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00240     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00241     cpl_parameterlist_append(recipe->parameters, p);
00242 
00243     /*
00244      * Sky lines alignment
00245      */
00246 
00247     p = cpl_parameter_new_value("fors.fors_align_sky.skyalign",
00248                                 CPL_TYPE_INT,
00249                                 "Polynomial order for sky lines alignment",
00250                                 "fors.fors_align_sky",
00251                                 0);
00252     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
00253     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00254     cpl_parameterlist_append(recipe->parameters, p);
00255 
00256     /*
00257      * Line catalog table column containing the sky reference wavelengths
00258      */
00259     
00260     p = cpl_parameter_new_value("fors.fors_align_sky.wcolumn",
00261                                 CPL_TYPE_STRING,
00262                                 "Name of sky line catalog table column "
00263                                 "with wavelengths",
00264                                 "fors.fors_align_sky",
00265                                 "WLEN");
00266     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00267     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00268     cpl_parameterlist_append(recipe->parameters, p);
00269 
00270     return 0;
00271 }
00272 
00273 
00282 static int fors_align_sky_exec(cpl_plugin *plugin)
00283 {
00284     cpl_recipe *recipe;
00285     
00286     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00287         recipe = (cpl_recipe *)plugin;
00288     else 
00289         return -1;
00290 
00291     return fors_align_sky(recipe->parameters, recipe->frames);
00292 }
00293 
00294 
00303 static int fors_align_sky_destroy(cpl_plugin *plugin)
00304 {
00305     cpl_recipe *recipe;
00306     
00307     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00308         recipe = (cpl_recipe *)plugin;
00309     else 
00310         return -1;
00311 
00312     cpl_parameterlist_delete(recipe->parameters); 
00313 
00314     return 0;
00315 }
00316 
00317 
00327 static int fors_align_sky(cpl_parameterlist *parlist, 
00328                                cpl_frameset *frameset)
00329 {
00330 
00331     const char *recipe = "fors_align_sky";
00332 
00333 
00334     /*
00335      * Input parameters
00336      */
00337 
00338     double      dispersion;
00339     double      startwavelength;
00340     double      endwavelength;
00341     int         skyalign;
00342     const char *wcolumn;
00343 
00344     /*
00345      * CPL objects
00346      */
00347 
00348     cpl_image        *rainbow     = NULL;
00349     cpl_image        *wavemap     = NULL;
00350     cpl_image        *smapped     = NULL;
00351     cpl_image        *coordinate  = NULL;
00352     cpl_table        *grism_table = NULL;
00353     cpl_table        *wavelengths = NULL;
00354     cpl_table        *slits       = NULL;
00355     cpl_table        *idscoeff    = NULL;
00356     cpl_table        *polytraces  = NULL;
00357     cpl_table        *maskslits   = NULL;
00358     cpl_table        *offsets     = NULL;
00359     cpl_vector       *lines       = NULL;
00360     cpl_propertylist *header      = NULL;
00361 
00362     /*
00363      * Auxiliary variables
00364      */
00365 
00366     char        version[80];
00367     const char *slit_location_tag;
00368     const char *curv_coeff_tag;
00369     const char *rectified_tag;
00370     const char *wavemap_tag;
00371     const char *shifts_tag;
00372     const char *disp_ali_tag;
00373     const char *disp_coeff_tag;
00374     const char *spatial_map_tag;
00375     int         nframes;
00376     int         rebin;
00377     int         nslits;
00378     int         nlines;
00379     int         nx;
00380     int         highres;
00381     int         treat_as_lss;
00382     int         i;
00383     double      reference;
00384     double     *xpos;
00385     double      mxpos;
00386     double     *line;
00387     int         mxu, mos;
00388     int         rec_scia;
00389     int         rec_stda;
00390     int         rec_scis;
00391     int         rec_stds;
00392     int         nslits_out_det = 0;
00393 
00394 
00395     char       *instrume = NULL;
00396 
00397 
00398     cpl_msg_set_indentation(2);
00399 
00400     if (dfs_files_dont_exist(frameset))
00401         fors_align_sky_exit(NULL);
00402 
00403 
00404     /*
00405      * Get configuration parameters
00406      */
00407 
00408     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00409     cpl_msg_indent_more();
00410     
00411     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00412         fors_align_sky_exit("Too many in input: GRISM_TABLE"); 
00413 
00414     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00415 
00416     dispersion = dfs_get_parameter_double(parlist,
00417                     "fors.fors_align_sky.dispersion", grism_table);
00418 
00419     if (dispersion <= 0.0)
00420         fors_align_sky_exit("Invalid spectral dispersion value");
00421 
00422     startwavelength = dfs_get_parameter_double(parlist,
00423                     "fors.fors_align_sky.startwavelength", grism_table);
00424     if (startwavelength > 1.0)
00425         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00426             fors_align_sky_exit("Invalid wavelength");
00427 
00428     endwavelength = dfs_get_parameter_double(parlist,
00429                     "fors.fors_align_sky.endwavelength", grism_table);
00430     if (endwavelength > 1.0) {
00431         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00432             fors_align_sky_exit("Invalid wavelength");
00433         if (startwavelength < 1.0)
00434             fors_align_sky_exit("Invalid wavelength interval");
00435     }
00436 
00437     if (startwavelength > 1.0)
00438         if (endwavelength - startwavelength <= 0.0)
00439             fors_align_sky_exit("Invalid wavelength interval");
00440 
00441     skyalign = dfs_get_parameter_int(parlist,
00442                     "fors.fors_align_sky.skyalign", NULL);
00443 
00444     if (skyalign < 0)
00445         fors_align_sky_exit("Invalid polynomial degree");
00446     if (skyalign > 2)
00447         fors_align_sky_exit("Max polynomial degree for sky alignment is 2");
00448 
00449     wcolumn = dfs_get_parameter_string(parlist,
00450                     "fors.fors_align_sky.wcolumn", NULL);
00451 
00452     cpl_table_delete(grism_table); grism_table = NULL;
00453 
00454     if (cpl_error_get_code())
00455         fors_align_sky_exit("Failure reading the configuration parameters");
00456 
00457 
00458     cpl_msg_indent_less();
00459     cpl_msg_info(recipe, "Check input set-of-frames:");
00460     cpl_msg_indent_more();
00461 
00462     mxu  = cpl_frameset_count_tags(frameset, "SPATIAL_MAP_MXU");
00463     mos  = cpl_frameset_count_tags(frameset, "SPATIAL_MAP_MOS");
00464 
00465     nframes = mos + mxu;
00466 
00467     if (nframes == 0) {
00468         fors_align_sky_exit("Missing input spatial map");
00469     }
00470     if (nframes > 1) {
00471         cpl_msg_error(recipe, 
00472                       "Too many input spatial maps (%d > 1)", nframes);
00473         fors_align_sky_exit(NULL);
00474     }
00475 
00476     if (mxu) {
00477         rec_scia = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_SCI_MXU");
00478         rec_stda = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_STD_MXU");
00479         rec_scis = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_SCI_MXU");
00480         rec_stds = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_STD_MXU");
00481     }
00482     else {
00483         rec_scia = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_SCI_MOS");
00484         rec_stda = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_STD_MOS");
00485         rec_scis = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_SCI_MOS");
00486         rec_stds = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_STD_MOS");
00487     }
00488 
00489     nframes = rec_scia + rec_stda + rec_scis + rec_stds;
00490 
00491     if (nframes == 0) {
00492         fors_align_sky_exit("Missing input rectified scientific spectra");
00493     }
00494     if (nframes > 1) {
00495         cpl_msg_error(recipe,
00496                       "Too many input rectified scientific spectra (%d > 1)", 
00497                       nframes);
00498         fors_align_sky_exit(NULL);
00499     }
00500 
00501     if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
00502         fors_align_sky_exit("Too many in input: MASTER_SKYLINECAT");
00503 
00504     if (rec_scia) {
00505         if (mxu) {
00506             rectified_tag = "RECTIFIED_ALL_SCI_MXU";
00507             wavemap_tag   = "WAVELENGTH_MAP_SCI_MXU";
00508             shifts_tag    = "SKY_SHIFTS_SLIT_SCI_MXU";
00509             disp_ali_tag  = "DISP_COEFF_SCI_MXU";
00510         }
00511         else {
00512             rectified_tag = "RECTIFIED_ALL_SCI_MOS";
00513             wavemap_tag   = "WAVELENGTH_MAP_SCI_MOS";
00514             shifts_tag    = "SKY_SHIFTS_SLIT_SCI_MOS";
00515             disp_ali_tag  = "DISP_COEFF_SCI_MOS";
00516         }
00517     }
00518     else if (rec_stda) {
00519         if (mxu) {
00520             rectified_tag = "RECTIFIED_ALL_STD_MXU";
00521             wavemap_tag   = "WAVELENGTH_MAP_STD_MXU";
00522             shifts_tag    = "SKY_SHIFTS_SLIT_STD_MXU";
00523             disp_ali_tag  = "DISP_COEFF_STD_MXU";
00524         }
00525         else {
00526             rectified_tag = "RECTIFIED_ALL_STD_MOS";
00527             wavemap_tag   = "WAVELENGTH_MAP_STD_MOS";
00528             shifts_tag    = "SKY_SHIFTS_SLIT_STD_MOS";
00529             disp_ali_tag  = "DISP_COEFF_STD_MOS";
00530         }
00531     }
00532     else if (rec_scis) {
00533         if (mxu) {
00534             rectified_tag = "RECTIFIED_SKY_SCI_MXU";
00535             wavemap_tag   = "WAVELENGTH_MAP_SCI_MXU";
00536             shifts_tag    = "SKY_SHIFTS_SLIT_SCI_MXU";
00537             disp_ali_tag  = "DISP_COEFF_SCI_MXU";
00538         }
00539         else {
00540             rectified_tag = "RECTIFIED_SKY_SCI_MOS";
00541             wavemap_tag   = "WAVELENGTH_MAP_SCI_MOS";
00542             shifts_tag    = "SKY_SHIFTS_SLIT_SCI_MOS";
00543             disp_ali_tag  = "DISP_COEFF_SCI_MOS";
00544         }
00545     }
00546     else if (rec_stds) {
00547         if (mxu) {
00548             rectified_tag = "RECTIFIED_SKY_STD_MXU";
00549             wavemap_tag   = "WAVELENGTH_MAP_STD_MXU";
00550             shifts_tag    = "SKY_SHIFTS_SLIT_STD_MXU";
00551             disp_ali_tag  = "DISP_COEFF_STD_MXU";
00552         }
00553         else {
00554             rectified_tag = "RECTIFIED_SKY_STD_MOS";
00555             wavemap_tag   = "WAVELENGTH_MAP_STD_MOS";
00556             shifts_tag    = "SKY_SHIFTS_SLIT_STD_MOS";
00557             disp_ali_tag  = "DISP_COEFF_STD_MOS";
00558         }
00559     }
00560 
00561 
00562     if (mxu) {
00563         disp_coeff_tag    = "DISP_COEFF_MXU";
00564         curv_coeff_tag    = "CURV_COEFF_MXU";
00565         slit_location_tag = "SLIT_LOCATION_MXU";
00566         spatial_map_tag   = "SPATIAL_MAP_MXU";
00567     }
00568     else {
00569         disp_coeff_tag    = "DISP_COEFF_MOS";
00570         curv_coeff_tag    = "CURV_COEFF_MOS";
00571         slit_location_tag = "SLIT_LOCATION_MOS";
00572         spatial_map_tag   = "SPATIAL_MAP_MOS";
00573     }
00574 
00575     nframes = cpl_frameset_count_tags(frameset, disp_coeff_tag);
00576 
00577     if (nframes == 0) {
00578         cpl_msg_error(recipe, "Missing input %s\n", disp_coeff_tag);
00579         fors_align_sky_exit(NULL);
00580     }
00581     if (nframes > 1) {
00582         cpl_msg_error(recipe, 
00583                       "Too many input %s (%d > 1)", disp_coeff_tag, nframes);
00584         fors_align_sky_exit(NULL);
00585     }
00586 
00587     nframes = cpl_frameset_count_tags(frameset, curv_coeff_tag);
00588 
00589     if (nframes == 0) {
00590         cpl_msg_error(recipe, "Missing input %s\n", curv_coeff_tag);
00591         fors_align_sky_exit(NULL);
00592     }
00593     if (nframes > 1) {
00594         cpl_msg_error(recipe,
00595                       "Too many input %s (%d > 1)", curv_coeff_tag, nframes);
00596         fors_align_sky_exit(NULL);
00597     }
00598 
00599     nframes = cpl_frameset_count_tags(frameset, spatial_map_tag);
00600 
00601     if (nframes == 0) {
00602         cpl_msg_error(recipe, "Missing input %s\n", spatial_map_tag);
00603         fors_align_sky_exit(NULL);
00604     }
00605     if (nframes > 1) {
00606         cpl_msg_error(recipe,
00607                       "Too many input %s (%d > 1)", spatial_map_tag, nframes);
00608         fors_align_sky_exit(NULL);
00609     }
00610     
00611 
00612     header = dfs_load_header(frameset, spatial_map_tag, 0);
00613 
00614     if (header == NULL)
00615         fors_align_sky_exit("Cannot load spatial map header");
00616 
00617     if (mos)
00618         maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00619     else
00620         maskslits = mos_load_slits_fors_mxu(header);
00621 
00622     /*
00623      * Check if all slits have the same X offset: in such case, abort!
00624      */
00625 
00626     treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
00627 
00628     cpl_table_delete(maskslits); maskslits = NULL;
00629 
00630     if (treat_as_lss) {
00631         cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00632                       "The LSS data reduction strategy must be applied. "
00633                       "Please use recipe fors_align_sky_lss.", mxpos);
00634         fors_align_sky_exit(NULL);
00635     }
00636 
00637     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00638         fors_align_sky_exit("Input frames are not from the same grism");
00639 
00640     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00641         fors_align_sky_exit("Input frames are not from the same filter");
00642 
00643     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00644         fors_align_sky_exit("Input frames are not from the same chip");
00645 
00646 
00647     /*
00648      * Get the reference wavelength and the rebin factor along the
00649      * dispersion direction from the reference frame
00650      */
00651 
00652     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00653     if (instrume == NULL)
00654         fors_align_sky_exit("Missing keyword INSTRUME in reference frame "
00655                             "header");
00656 
00657     if (instrume[4] == '1')
00658         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00659     if (instrume[4] == '2')
00660         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00661 
00662     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00663 
00664     if (cpl_error_get_code() != CPL_ERROR_NONE)
00665         fors_align_sky_exit("Missing keyword ESO INS GRIS1 WLEN "
00666                             "in reference frame header");
00667 
00668     if (reference < 3000.0)   /* Perhaps in nanometers... */
00669         reference *= 10;
00670 
00671     if (reference < 3000.0 || reference > 13000.0) {
00672         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00673                       "keyword ESO INS GRIS1 WLEN in reference frame header",
00674                       reference);
00675         fors_align_sky_exit(NULL);
00676     }
00677 
00678     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00679 
00680     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00681 
00682     if (cpl_error_get_code() != CPL_ERROR_NONE)
00683         fors_align_sky_exit("Missing keyword ESO DET WIN1 BINX "
00684                             "in reference frame header");
00685 
00686     if (rebin != 1) {
00687         dispersion *= rebin;
00688         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00689                         "working dispersion used is %f A/pixel", rebin,
00690                         dispersion);
00691     }
00692 
00693     cpl_msg_indent_less();
00694     cpl_msg_info(recipe, "Load input frames...");
00695     cpl_msg_indent_more();
00696 
00697     coordinate = dfs_load_image(frameset, spatial_map_tag, 
00698                                 CPL_TYPE_FLOAT, 0, 0);
00699     if (coordinate == NULL)
00700         fors_align_sky_exit("Cannot load input reference frame");
00701 
00702     slits = dfs_load_table(frameset, slit_location_tag, 1);
00703     if (slits == NULL)
00704         fors_align_sky_exit("Cannot load slits location table");
00705 
00706     polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00707     if (polytraces == NULL)
00708         fors_align_sky_exit("Cannot load spectral curvature table");
00709 
00710     idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
00711     if (idscoeff == NULL)
00712         fors_align_sky_exit("Cannot load dispersion solution");
00713 
00714     smapped = dfs_load_image(frameset, rectified_tag, CPL_TYPE_FLOAT, 0, 0);
00715     if (smapped == NULL)
00716         fors_align_sky_exit("Cannot load input rectified frame");
00717 
00718     wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
00719 
00720     if (wavelengths) {
00721 
00722         /*
00723          * Cast the wavelengths into a (double precision) CPL vector
00724          */
00725 
00726         nlines = cpl_table_get_nrow(wavelengths);
00727 
00728         if (nlines == 0)
00729             fors_align_sky_exit("Empty input sky line catalog");
00730 
00731         if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00732             cpl_msg_error(recipe, "Missing column %s in input line "
00733                           "catalog table", wcolumn);
00734             fors_align_sky_exit(NULL);
00735         }
00736 
00737         line = cpl_malloc(nlines * sizeof(double));
00738 
00739         for (i = 0; i < nlines; i++)
00740             line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00741 
00742         cpl_table_delete(wavelengths); wavelengths = NULL;
00743 
00744         lines = cpl_vector_wrap(nlines, line);
00745     }
00746     else {
00747         cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
00748     }
00749 
00750     if (skyalign) {
00751         cpl_msg_info(recipe, "Align wavelength solution to reference "
00752         "skylines applying %d order residual fit...", skyalign);
00753     }
00754     else {
00755         cpl_msg_info(recipe, "Align wavelength solution to reference "
00756         "skylines applying median offset...");
00757     }
00758 
00759     if (dispersion > 1.0)
00760         highres = 0;
00761     else
00762         highres = 1;
00763 
00764     nx = cpl_image_get_size_x(coordinate);
00765 
00766     rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
00767                                endwavelength);
00768 
00769     offsets = mos_wavelength_align(smapped, slits, reference,
00770                                    startwavelength, endwavelength,
00771                                    idscoeff, lines, highres, skyalign,
00772                                    rainbow, 4);
00773 
00774     cpl_vector_delete(lines); lines = NULL;
00775     cpl_image_delete(smapped); smapped = NULL;
00776 
00777     if (offsets) {
00778         if (dfs_save_table(frameset, offsets, shifts_tag, NULL,
00779                            parlist, recipe, version))
00780             fors_align_sky_exit(NULL);
00781 
00782         cpl_table_delete(offsets); offsets = NULL;
00783     }
00784     else
00785         fors_align_sky_exit("Alignment of the wavelength solution "
00786                         "to reference sky lines could not be done!");
00787 
00788     if (dfs_save_table(frameset, idscoeff, disp_ali_tag, NULL,
00789                        parlist, recipe, version))
00790         fors_align_sky_exit(NULL);
00791 
00792     cpl_table_delete(idscoeff); idscoeff = NULL;
00793 
00794     wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
00795                                   polytraces, reference,
00796                                   startwavelength, endwavelength,
00797                                   dispersion);
00798 
00799     cpl_image_delete(rainbow); rainbow = NULL;
00800     cpl_image_delete(coordinate); coordinate = NULL;
00801     cpl_table_delete(polytraces); polytraces = NULL;
00802     cpl_table_delete(slits); slits = NULL;
00803 
00804     if (dfs_save_image(frameset, wavemap, wavemap_tag,
00805                        header, parlist, recipe, version))
00806         fors_align_sky_exit(NULL);
00807 
00808     cpl_image_delete(wavemap); wavemap = NULL;
00809     cpl_propertylist_delete(header); header = NULL;
00810 
00811     return 0;
00812 }