fors_wave_calib.c

00001 /* $Id: fors_wave_calib.c,v 1.5 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.5 $
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_wave_calib_create(cpl_plugin *);
00038 static int fors_wave_calib_exec(cpl_plugin *);
00039 static int fors_wave_calib_destroy(cpl_plugin *);
00040 static int fors_wave_calib(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char fors_wave_calib_description[] =
00043 "This recipe is used to wavelength calibrate MOS/MXU slit spectra contained\n"
00044 "in the rectified arc lamp exposure produced with recipe fors_extract_slits.\n"
00045 "A pattern-matching algorithm is applied as in recipe fors_detect_spectra.\n"
00046 "The input spatial map is used in the production of the wavelength map.\n"
00047 "\n"
00048 "Use recipe fors_wave_calib_lss for LSS data, or for MOS/MXU data where all\n"
00049 "slits have the same offset. For more details on this data reduction strategy\n"
00050 "please refer to the FORS Pipeline User's Manual.\n"
00051 "\n"
00052 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
00053 "configuration parameters to default values valid for a particular grism.\n"
00054 "\n"
00055 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
00056 "Input files:\n\n"
00057 "  DO category:               Type:       Explanation:         Required:\n"
00058 "  SPATIAL_MAP_MXU            Calib       Spatial map             Y\n"
00059 "  RECTIFIED_LAMP_MXU         Calib       Rectified arc exposure  Y\n"
00060 "  SLIT_LOCATION_MXU          Calib       Slit location table     Y\n"
00061 "  CURV_COEFF_MXU             Calib       Spectral curvature      Y\n"
00062 "  MASTER_LINECAT             Calib       Line catalog            Y\n"
00063 "  GRISM_TABLE                Calib       Grism table             .\n\n"
00064 "Output files:\n\n"
00065 "  DO category:               Data type:  Explanation:\n"
00066 "  REDUCED_LAMP_MXU           FITS image  Calibrated arc lamp exposure\n"
00067 "  DISP_COEFF_MXU             FITS table  Inverse dispersion coefficients\n"
00068 "  DISP_RESIDUALS_MXU         FITS image  Image of modeling residuals\n"
00069 "  WAVELENGTH_MAP_MXU         FITS image  Wavelengths mapped on CCD\n"
00070 "  SPECTRAL_RESOLUTION_MXU    FITS table  Spectral resolution table\n\n";
00071 
00072 #define fors_wave_calib_exit(message)         \
00073 {                                             \
00074 if (message) cpl_msg_error(recipe, message);  \
00075 cpl_image_delete(spectra);                    \
00076 cpl_image_delete(spatial);                    \
00077 cpl_image_delete(rainbow);                    \
00078 cpl_image_delete(residual);                   \
00079 cpl_image_delete(rectified);                  \
00080 cpl_image_delete(wavemap);                    \
00081 cpl_table_delete(grism_table);                \
00082 cpl_table_delete(wavelengths);                \
00083 cpl_table_delete(maskslits);                  \
00084 cpl_table_delete(idscoeff);                   \
00085 cpl_table_delete(restab);                     \
00086 cpl_table_delete(slits);                      \
00087 cpl_table_delete(polytraces);                 \
00088 cpl_vector_delete(lines);                     \
00089 cpl_propertylist_delete(header);              \
00090 cpl_propertylist_delete(save_header);         \
00091 cpl_msg_indent_less();                        \
00092 return -1;                                    \
00093 }
00094 
00095 #define fors_wave_calib_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 spatial (%p)\n", spatial);         \
00101 cpl_image_delete(spatial);                      \
00102 printf("free rainbow (%p)\n", rainbow);         \
00103 cpl_image_delete(rainbow);                      \
00104 printf("free residual (%p)\n", residual);       \
00105 cpl_image_delete(residual);                     \
00106 printf("free rectified (%p)\n", rectified);     \
00107 cpl_image_delete(rectified);                    \
00108 printf("free wavemap (%p)\n", wavemap);         \
00109 cpl_image_delete(wavemap);                      \
00110 printf("free grism_table (%p)\n", grism_table); \
00111 cpl_table_delete(grism_table);                  \
00112 printf("free wavelengths (%p)\n", wavelengths); \
00113 cpl_table_delete(wavelengths);                  \
00114 printf("free maskslits (%p)\n", maskslits);     \
00115 cpl_table_delete(maskslits);                    \
00116 printf("free idscoeff (%p)\n", idscoeff);       \
00117 cpl_table_delete(idscoeff);                     \
00118 printf("free restab (%p)\n", restab);           \
00119 cpl_table_delete(restab);                       \
00120 printf("free slits (%p)\n", slits);             \
00121 cpl_table_delete(slits);                        \
00122 printf("free polytraces (%p)\n", polytraces);   \
00123 cpl_table_delete(polytraces);                   \
00124 printf("free lines (%p)\n", lines);             \
00125 cpl_vector_delete(lines);                       \
00126 printf("free header (%p)\n", header);           \
00127 cpl_propertylist_delete(header);                \
00128 printf("free save_header (%p)\n", save_header); \
00129 cpl_propertylist_delete(save_header);           \
00130 cpl_msg_indent_less();                          \
00131 return 0;                                       \
00132 }
00133 
00134 
00146 int cpl_plugin_get_info(cpl_pluginlist *list)
00147 {
00148     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00149     cpl_plugin *plugin = &recipe->interface;
00150 
00151     cpl_plugin_init(plugin,
00152                     CPL_PLUGIN_API,
00153                     FORS_BINARY_VERSION,
00154                     CPL_PLUGIN_TYPE_RECIPE,
00155                     "fors_wave_calib",
00156                     "Derive dispersion relation from rectified arc lamp frame",
00157                     fors_wave_calib_description,
00158                     "Carlo Izzo",
00159                     PACKAGE_BUGREPORT,
00160     "This file is currently part of the FORS Instrument Pipeline\n"
00161     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00162     "This program is free software; you can redistribute it and/or modify\n"
00163     "it under the terms of the GNU General Public License as published by\n"
00164     "the Free Software Foundation; either version 2 of the License, or\n"
00165     "(at your option) any later version.\n\n"
00166     "This program is distributed in the hope that it will be useful,\n"
00167     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00168     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00169     "GNU General Public License for more details.\n\n"
00170     "You should have received a copy of the GNU General Public License\n"
00171     "along with this program; if not, write to the Free Software Foundation,\n"
00172     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00173                     fors_wave_calib_create,
00174                     fors_wave_calib_exec,
00175                     fors_wave_calib_destroy);
00176 
00177     cpl_pluginlist_append(list, plugin);
00178     
00179     return 0;
00180 }
00181 
00182 
00193 static int fors_wave_calib_create(cpl_plugin *plugin)
00194 {
00195     cpl_recipe    *recipe;
00196     cpl_parameter *p;
00197 
00198     /* 
00199      * Check that the plugin is part of a valid recipe 
00200      */
00201 
00202     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00203         recipe = (cpl_recipe *)plugin;
00204     else 
00205         return -1;
00206 
00207     /* 
00208      * Create the (empty) parameters list in the cpl_recipe object 
00209      */
00210 
00211     recipe->parameters = cpl_parameterlist_new(); 
00212 
00213     /*
00214      * Dispersion
00215      */
00216 
00217     p = cpl_parameter_new_value("fors.fors_wave_calib.dispersion",
00218                                 CPL_TYPE_DOUBLE,
00219                                 "Expected spectral dispersion (Angstrom/pixel)",
00220                                 "fors.fors_wave_calib",
00221                                 0.0);
00222     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00223     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00224     cpl_parameterlist_append(recipe->parameters, p);
00225 
00226     /*
00227      * Peak detection level
00228      */
00229 
00230     p = cpl_parameter_new_value("fors.fors_wave_calib.peakdetection",
00231                                 CPL_TYPE_DOUBLE,
00232                                 "Initial peak detection threshold (ADU)",
00233                                 "fors.fors_wave_calib",
00234                                 0.0);
00235     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection");
00236     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00237     cpl_parameterlist_append(recipe->parameters, p);
00238 
00239     /*
00240      * Degree of wavelength calibration polynomial
00241      */
00242 
00243     p = cpl_parameter_new_value("fors.fors_wave_calib.wdegree",
00244                                 CPL_TYPE_INT,
00245                                 "Degree of wavelength calibration polynomial",
00246                                 "fors.fors_wave_calib",
00247                                 0);
00248     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree");
00249     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00250     cpl_parameterlist_append(recipe->parameters, p);
00251 
00252     /*
00253      * Reference lines search radius
00254      */
00255 
00256     p = cpl_parameter_new_value("fors.fors_wave_calib.wradius",
00257                                 CPL_TYPE_INT,
00258                                 "Search radius if iterating pattern-matching "
00259                                 "with first-guess method",
00260                                 "fors.fors_wave_calib",
00261                                 4);
00262     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius");
00263     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00264     cpl_parameterlist_append(recipe->parameters, p);
00265 
00266     /*
00267      * Rejection threshold in dispersion relation polynomial fitting
00268      */
00269 
00270     p = cpl_parameter_new_value("fors.fors_wave_calib.wreject",
00271                                 CPL_TYPE_DOUBLE,
00272                                 "Rejection threshold in dispersion "
00273                                 "relation fit (pixel)",
00274                                 "fors.fors_wave_calib",
00275                                 0.7);
00276     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject");
00277     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00278     cpl_parameterlist_append(recipe->parameters, p);
00279 
00280     /*
00281      * Line catalog table column containing the reference wavelengths
00282      */
00283 
00284     p = cpl_parameter_new_value("fors.fors_wave_calib.wcolumn",
00285                                 CPL_TYPE_STRING,
00286                                 "Name of line catalog table column "
00287                                 "with wavelengths",
00288                                 "fors.fors_wave_calib",
00289                                 "WLEN");
00290     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
00291     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00292     cpl_parameterlist_append(recipe->parameters, p);
00293 
00294     /*
00295      * Start wavelength for spectral extraction
00296      */
00297 
00298     p = cpl_parameter_new_value("fors.fors_wave_calib.startwavelength",
00299                                 CPL_TYPE_DOUBLE,
00300                                 "Start wavelength in spectral extraction",
00301                                 "fors.fors_wave_calib",
00302                                 0.0);
00303     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00304     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00305     cpl_parameterlist_append(recipe->parameters, p);
00306 
00307     /*
00308      * End wavelength for spectral extraction
00309      */
00310 
00311     p = cpl_parameter_new_value("fors.fors_wave_calib.endwavelength",
00312                                 CPL_TYPE_DOUBLE,
00313                                 "End wavelength in spectral extraction",
00314                                 "fors.fors_wave_calib",
00315                                 0.0);
00316     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00317     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00318     cpl_parameterlist_append(recipe->parameters, p);
00319 
00320     return 0;
00321 }
00322 
00323 
00332 static int fors_wave_calib_exec(cpl_plugin *plugin)
00333 {
00334     cpl_recipe *recipe;
00335     
00336     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00337         recipe = (cpl_recipe *)plugin;
00338     else 
00339         return -1;
00340 
00341     return fors_wave_calib(recipe->parameters, recipe->frames);
00342 }
00343 
00344 
00353 static int fors_wave_calib_destroy(cpl_plugin *plugin)
00354 {
00355     cpl_recipe *recipe;
00356     
00357     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00358         recipe = (cpl_recipe *)plugin;
00359     else 
00360         return -1;
00361 
00362     cpl_parameterlist_delete(recipe->parameters); 
00363 
00364     return 0;
00365 }
00366 
00367 
00377 static int fors_wave_calib(cpl_parameterlist *parlist, 
00378                                cpl_frameset *frameset)
00379 {
00380 
00381     const char *recipe = "fors_wave_calib";
00382 
00383 
00384     /*
00385      * Input parameters
00386      */
00387 
00388     double      dispersion;
00389     double      peakdetection;
00390     int         wdegree;
00391     int         wradius;
00392     double      wreject;
00393     const char *wcolumn;
00394     double      startwavelength;
00395     double      endwavelength;
00396 
00397     /*
00398      * CPL objects
00399      */
00400 
00401     cpl_image        *spectra     = NULL;
00402     cpl_image        *spatial     = NULL;
00403     cpl_image        *rectified   = NULL;
00404     cpl_image        *wavemap     = NULL;
00405     cpl_image        *rainbow     = NULL;
00406     cpl_image        *residual    = NULL;
00407     cpl_image        *bimage      = NULL;
00408     cpl_table        *grism_table = NULL;
00409     cpl_table        *wavelengths = NULL;
00410     cpl_table        *slits       = NULL;
00411     cpl_table        *polytraces  = NULL;
00412     cpl_table        *idscoeff    = NULL;
00413     cpl_table        *maskslits   = NULL;
00414     cpl_table        *restab      = NULL;
00415     cpl_vector       *lines       = NULL;
00416     cpl_propertylist *header      = NULL;
00417     cpl_propertylist *save_header = NULL;
00418 
00419     /*
00420      * Auxiliary variables
00421      */
00422 
00423     char        version[80];
00424     const char *arc_tag;
00425     const char *reduced_lamp_tag;
00426     const char *wavelength_map_tag;
00427     const char *spatial_map_tag;
00428     const char *disp_residuals_tag;
00429     const char *disp_coeff_tag;
00430     const char *curv_coeff_tag;
00431     const char *slit_location_tag;
00432     const char *spectral_resolution_tag;
00433     int         lamp_mxu;
00434     int         lamp_mos;
00435     int         mxu, mos;
00436     int         treat_as_lss = 0;
00437     int         nslits;
00438     double      mean_rms;
00439     double     *xpos;
00440     double      mxpos;
00441     int         narc, nref;
00442     int         nlines;
00443     int         rebin;
00444     double     *line;
00445     double     *fiterror = NULL;
00446     int        *fitlines = NULL;
00447     int         nx, ny;
00448     double      reference;
00449     int         i;
00450 
00451     char       *instrume = NULL;
00452 
00453 
00454     cpl_msg_set_indentation(2);
00455 
00456     if (dfs_files_dont_exist(frameset))
00457         fors_wave_calib_exit(NULL);
00458 
00459 
00460     /*
00461      * Get configuration parameters
00462      */
00463 
00464     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00465     cpl_msg_indent_more();
00466     
00467     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00468         fors_wave_calib_exit("Too many in input: GRISM_TABLE"); 
00469 
00470     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00471 
00472     dispersion = dfs_get_parameter_double(parlist,
00473                     "fors.fors_wave_calib.dispersion", grism_table);
00474 
00475     if (dispersion <= 0.0)
00476         fors_wave_calib_exit("Invalid spectral dispersion value");
00477 
00478     peakdetection = dfs_get_parameter_double(parlist,
00479                     "fors.fors_wave_calib.peakdetection", grism_table);
00480     if (peakdetection <= 0.0)
00481         fors_wave_calib_exit("Invalid peak detection level");
00482 
00483     wdegree = dfs_get_parameter_int(parlist,
00484                     "fors.fors_wave_calib.wdegree", grism_table);
00485 
00486     if (wdegree < 1)
00487         fors_wave_calib_exit("Invalid polynomial degree");
00488 
00489     if (wdegree > 5)
00490         fors_wave_calib_exit("Max allowed polynomial degree is 5");
00491 
00492     wradius = dfs_get_parameter_int(parlist, 
00493                                     "fors.fors_wave_calib.wradius", NULL);
00494 
00495     if (wradius < 0)
00496         fors_wave_calib_exit("Invalid search radius");
00497 
00498     wreject = dfs_get_parameter_double(parlist, 
00499                                     "fors.fors_wave_calib.wreject", NULL);
00500 
00501     if (wreject <= 0.0)
00502         fors_wave_calib_exit("Invalid rejection threshold");
00503 
00504     wcolumn = dfs_get_parameter_string(parlist, 
00505                                     "fors.fors_wave_calib.wcolumn", NULL);
00506 
00507     startwavelength = dfs_get_parameter_double(parlist,
00508                     "fors.fors_wave_calib.startwavelength", grism_table);
00509     if (startwavelength > 1.0)
00510         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00511             fors_wave_calib_exit("Invalid wavelength");
00512 
00513     endwavelength = dfs_get_parameter_double(parlist,
00514                     "fors.fors_wave_calib.endwavelength", grism_table);
00515     if (endwavelength > 1.0) {
00516         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00517             fors_wave_calib_exit("Invalid wavelength");
00518         if (startwavelength < 1.0)
00519             fors_wave_calib_exit("Invalid wavelength interval");
00520     }
00521 
00522     if (startwavelength > 1.0)
00523         if (endwavelength - startwavelength <= 0.0)
00524             fors_wave_calib_exit("Invalid wavelength interval");
00525 
00526     cpl_table_delete(grism_table); grism_table = NULL;
00527 
00528     if (cpl_error_get_code())
00529         fors_wave_calib_exit("Failure reading the configuration parameters");
00530 
00531 
00532     cpl_msg_indent_less();
00533     cpl_msg_info(recipe, "Check input set-of-frames:");
00534     cpl_msg_indent_more();
00535 
00536     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00537         fors_wave_calib_exit("Missing required input: MASTER_LINECAT");
00538 
00539     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00540         fors_wave_calib_exit("Too many in input: MASTER_LINECAT");
00541 
00542     lamp_mxu = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MXU");
00543     lamp_mos = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MOS");
00544 
00545     narc = lamp_mxu + lamp_mos;
00546 
00547     if (narc == 0) {
00548         fors_wave_calib_exit("Missing input rectified arc lamp frame");
00549     }
00550     if (narc > 1) {
00551         cpl_msg_error(recipe, "Too many input rectified arc lamp frames "
00552                       "(%d > 1)", narc);
00553         fors_wave_calib_exit(NULL);
00554     }
00555 
00556     mxu = mos = 0;
00557 
00558     if (lamp_mxu) {
00559         mxu = 1;
00560         arc_tag                 = "RECTIFIED_LAMP_MXU";
00561         slit_location_tag       = "SLIT_LOCATION_MXU";
00562         spatial_map_tag         = "SPATIAL_MAP_MXU";
00563         reduced_lamp_tag        = "REDUCED_LAMP_MXU";
00564         disp_residuals_tag      = "DISP_RESIDUALS_MXU";
00565         disp_coeff_tag          = "DISP_COEFF_MXU";
00566         curv_coeff_tag          = "CURV_COEFF_MXU";
00567         wavelength_map_tag      = "WAVELENGTH_MAP_MXU";
00568         spectral_resolution_tag = "SPECTRAL_RESOLUTION_MXU";
00569     }
00570     else if (lamp_mos) {
00571         mos = 1;
00572         arc_tag                 = "RECTIFIED_LAMP_MOS";
00573         slit_location_tag       = "SLIT_LOCATION_MOS";
00574         spatial_map_tag         = "SPATIAL_MAP_MOS";
00575         reduced_lamp_tag        = "REDUCED_LAMP_MOS";
00576         disp_residuals_tag      = "DISP_RESIDUALS_MOS";
00577         disp_coeff_tag          = "DISP_COEFF_MOS";
00578         curv_coeff_tag          = "CURV_COEFF_MXU";
00579         wavelength_map_tag      = "WAVELENGTH_MAP_MOS";
00580         spectral_resolution_tag = "SPECTRAL_RESOLUTION_MOS";
00581     }
00582 
00583 
00584     nref = cpl_frameset_count_tags(frameset, spatial_map_tag);
00585 
00586     if (nref == 0) {
00587         fors_wave_calib_exit("Missing input spatial map");
00588     }
00589     if (nref > 1) {
00590         cpl_msg_error(recipe, "Too many input spatial maps (%d > 1)", nref);
00591         fors_wave_calib_exit(NULL);
00592     }
00593 
00594     nref = cpl_frameset_count_tags(frameset, slit_location_tag);
00595 
00596     if (nref == 0) {
00597         fors_wave_calib_exit("Missing input slit location table");
00598     }
00599     if (nref > 1) {
00600         cpl_msg_error(recipe, "Too many input slit location tables (%d > 1)", 
00601                       nref);
00602         fors_wave_calib_exit(NULL);
00603     }
00604 
00605     nref = cpl_frameset_count_tags(frameset, curv_coeff_tag);
00606 
00607     if (nref == 0) {
00608         fors_wave_calib_exit("Missing input spectral curvature table");
00609     }
00610     if (nref > 1) {
00611         cpl_msg_error(recipe, "Too many input spectral curvature tables "
00612                       "(%d > 1)", nref);
00613         fors_wave_calib_exit(NULL);
00614     }
00615 
00616 
00617     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00618         fors_wave_calib_exit("Input frames are not from the same grism");
00619 
00620     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00621         fors_wave_calib_exit("Input frames are not from the same filter");
00622 
00623     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00624         fors_wave_calib_exit("Input frames are not from the same chip");
00625 
00626 
00627     /*
00628      * Get the reference wavelength and the rebin factor along the
00629      * dispersion direction from the arc lamp exposure
00630      */
00631 
00632     header = dfs_load_header(frameset, spatial_map_tag, 0);
00633 
00634     if (header == NULL)
00635         fors_wave_calib_exit("Cannot load arc lamp header");
00636 
00637     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00638     if (instrume == NULL)
00639         fors_wave_calib_exit("Missing keyword INSTRUME in arc lamp header");
00640 
00641     if (instrume[4] == '1')
00642         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00643     if (instrume[4] == '2')
00644         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00645 
00646     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00647 
00648     if (cpl_error_get_code() != CPL_ERROR_NONE)
00649         fors_wave_calib_exit("Missing keyword ESO INS GRIS1 WLEN "
00650                                  "in arc lamp frame header");
00651 
00652     if (reference < 3000.0)   /* Perhaps in nanometers... */
00653         reference *= 10;
00654 
00655     if (reference < 3000.0 || reference > 13000.0) {
00656         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00657                       "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00658                       reference);
00659         fors_wave_calib_exit(NULL);
00660     }
00661 
00662     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00663 
00664     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00665 
00666     if (cpl_error_get_code() != CPL_ERROR_NONE)
00667         fors_wave_calib_exit("Missing keyword ESO DET WIN1 BINX "
00668                                  "in arc lamp frame header");
00669 
00670     if (rebin != 1) {
00671         dispersion *= rebin;
00672         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00673                         "working dispersion used is %f A/pixel", rebin,
00674                         dispersion);
00675     }
00676 
00677 
00678     cpl_msg_info(recipe, "Produce mask slit position table...");
00679 
00680     if (mos)
00681         maskslits = mos_load_slits_fors_mos(header);
00682     else
00683         maskslits = mos_load_slits_fors_mxu(header);
00684 
00685 
00686     /*
00687      * Check if all slits have the same X offset: in such case,
00688      * treat the observation as a long-slit one!
00689      */
00690 
00691     mxpos = cpl_table_get_column_median(maskslits, "xtop");
00692     xpos = cpl_table_get_data_double(maskslits, "xtop");
00693     nslits = cpl_table_get_nrow(maskslits);
00694 
00695     treat_as_lss = 1;
00696     for (i = 0; i < nslits; i++) {
00697         if (fabs(mxpos-xpos[i]) > 0.01) {
00698             treat_as_lss = 0;
00699             break;
00700         }
00701     }
00702 
00703     cpl_table_delete(maskslits); maskslits = NULL;
00704 
00705     if (treat_as_lss) {
00706         cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00707                       "The LSS data reduction strategy must be applied: "
00708                       "please use recipe fors_wave_calib_lss", mxpos);
00709         fors_wave_calib_exit(NULL);
00710     }
00711 
00712 
00713     cpl_msg_indent_less();
00714     cpl_msg_info(recipe, "Load arc lamp exposure...");
00715     cpl_msg_indent_more();
00716 
00717     spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00718 
00719     if (spectra == NULL)
00720         fors_wave_calib_exit("Cannot load arc lamp exposure");
00721 
00722 
00723     cpl_msg_indent_less();
00724     cpl_msg_info(recipe, "Load input line catalog...");
00725     cpl_msg_indent_more();
00726 
00727     wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00728 
00729     if (wavelengths == NULL)
00730         fors_wave_calib_exit("Cannot load line catalog");
00731 
00732 
00733     /*
00734      * Cast the wavelengths into a (double precision) CPL vector
00735      */
00736 
00737     nlines = cpl_table_get_nrow(wavelengths);
00738 
00739     if (nlines == 0)
00740         fors_wave_calib_exit("Empty input line catalog");
00741 
00742     if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00743         cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00744                       wcolumn);
00745         fors_wave_calib_exit(NULL);
00746     }
00747 
00748     line = cpl_malloc(nlines * sizeof(double));
00749 
00750     for (i = 0; i < nlines; i++)
00751         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00752 
00753     cpl_table_delete(wavelengths); wavelengths = NULL;
00754 
00755     lines = cpl_vector_wrap(nlines, line);
00756 
00757 
00758     cpl_msg_indent_less();
00759     cpl_msg_info(recipe, "Load slit location table...");
00760     cpl_msg_indent_more();
00761 
00762     slits = dfs_load_table(frameset, slit_location_tag, 1);
00763 
00764     if (slits == NULL)
00765         fors_wave_calib_exit("Cannot load slit location table");
00766 
00767 
00768     cpl_msg_indent_less();
00769     cpl_msg_info(recipe, "Subtract background from input arc exposure...");
00770     cpl_msg_indent_more();
00771 
00772     bimage = mos_arc_background(spectra, 15, 15);
00773     cpl_image_subtract(spectra, bimage);
00774     cpl_image_delete(bimage);
00775 
00776 
00777     cpl_msg_indent_less();
00778     cpl_msg_info(recipe, "Perform wavelength calibration...");
00779     cpl_msg_indent_more();
00780 
00781     nx = cpl_image_get_size_x(spectra);
00782     ny = cpl_image_get_size_y(spectra);
00783 
00784     idscoeff = cpl_table_new(ny);
00785     rainbow  = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00786     residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00787     fiterror = cpl_calloc(ny, sizeof(double));
00788     fitlines = cpl_calloc(ny, sizeof(int));
00789 
00790     rectified = mos_wavelength_calibration_final(spectra, slits, lines, 
00791                                                  dispersion, peakdetection,
00792                                                  wradius, wdegree, wreject,
00793                                                  reference, &startwavelength,
00794                                                  &endwavelength, fitlines,
00795                                                  fiterror, idscoeff, rainbow,
00796                                                  residual, NULL);
00797 
00798     cpl_image_delete(spectra); spectra = NULL;
00799 
00800     if (rectified == NULL)
00801         fors_wave_calib_exit("Wavelength calibration failure");
00802 
00803     save_header = cpl_propertylist_new();
00804     cpl_propertylist_update_double(save_header, "CRPIX1", 1.0);
00805     cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00806     cpl_propertylist_update_double(save_header, "CRVAL1",
00807                                    startwavelength + dispersion/2);
00808     cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00809     /* cpl_propertylist_update_double(save_header, "CDELT1", dispersion);
00810     cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
00811     cpl_propertylist_update_double(save_header, "CD1_1", dispersion);
00812     cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00813     cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00814     cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00815     cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00816     cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00817     cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", 1);
00818 
00819     if (dfs_save_image(frameset, rectified, reduced_lamp_tag, save_header,
00820                        parlist, recipe, version))
00821         fors_wave_calib_exit(NULL);
00822 
00823     cpl_propertylist_delete(save_header); save_header = NULL;
00824     save_header = cpl_propertylist_new();
00825 
00826     cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00827     cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00828     /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
00829     cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
00830     cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00831     cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00832     cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00833     cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00834     cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00835 
00836     if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header,
00837                        parlist, recipe, version))
00838         fors_wave_calib_exit(NULL);
00839 
00840     cpl_propertylist_delete(save_header); save_header = NULL;
00841     cpl_image_delete(residual); residual = NULL;
00842 
00843     cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
00844     cpl_table_set_column_unit(idscoeff, "error", "pixel");
00845     cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
00846 
00847     for (i = 0; i < ny; i++)
00848         if (!cpl_table_is_valid(idscoeff, "c0", i))
00849             cpl_table_set_invalid(idscoeff, "error", i);
00850 
00851     if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
00852                        parlist, recipe, version))
00853         fors_wave_calib_exit(NULL);
00854 
00855     mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
00856                                    dispersion, 6, 0);
00857 
00858     cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
00859 
00860     mean_rms = cpl_table_get_column_mean(idscoeff, "error");
00861 
00862     cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
00863                  mean_rms, mean_rms * dispersion);
00864 
00865     cpl_table_delete(idscoeff); idscoeff = NULL;
00866 
00867     /*
00868      * Create resolution table
00869      */
00870 
00871     restab = mos_resolution_table(rectified, startwavelength, dispersion,
00872                                   60000, lines);
00873 
00874     cpl_vector_delete(lines); lines = NULL;
00875     cpl_image_delete(rectified); rectified = NULL;
00876 
00877     if (restab) {
00878         cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
00879                    cpl_table_get_column_mean(restab, "resolution"));
00880         cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel",
00881                    cpl_table_get_column_mean(restab, "fwhm") / dispersion,
00882                    cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
00883 
00884         if (dfs_save_table(frameset, restab, spectral_resolution_tag, NULL,
00885                            parlist, recipe, version))
00886             fors_wave_calib_exit(NULL);
00887 
00888         cpl_table_delete(restab); restab = NULL;
00889     }
00890     else
00891         fors_wave_calib_exit("Cannot compute the spectral resolution table");
00892 
00893 
00894     cpl_msg_indent_less();
00895     cpl_msg_info(recipe, "Load spatial map image...");
00896     cpl_msg_indent_more();
00897 
00898     spatial = dfs_load_image(frameset, spatial_map_tag, CPL_TYPE_FLOAT, 0, 0);
00899 
00900     if (spatial == NULL)
00901         fors_wave_calib_exit("Cannot load spatial map");
00902 
00903     cpl_msg_indent_less();
00904     cpl_msg_info(recipe, "Load spectral curvature table...");
00905     cpl_msg_indent_more();
00906 
00907     polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00908 
00909     if (polytraces == NULL)
00910         fors_wave_calib_exit("Cannot load spectral curvature table");
00911 
00912     wavemap = mos_map_wavelengths(spatial, rainbow, slits, polytraces,
00913                                   reference, startwavelength, endwavelength,
00914                                   dispersion);
00915 
00916     cpl_image_delete(rainbow); rainbow = NULL;
00917     cpl_image_delete(spatial); spatial = NULL;
00918     cpl_table_delete(slits); slits = NULL;
00919     cpl_table_delete(polytraces); polytraces = NULL;
00920 
00921     if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header,
00922                        parlist, recipe, version))
00923         fors_wave_calib_exit(NULL);
00924 
00925     cpl_image_delete(wavemap); wavemap = NULL;
00926     cpl_propertylist_delete(header); header = NULL;
00927 
00928     return 0;
00929 }

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