fors_wave_calib.c

00001 /* $Id: fors_wave_calib.c,v 1.9 2013-08-20 17:02:58 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-08-20 17:02:58 $
00024  * $Revision: 1.9 $
00025  * $Name: not supported by cvs2svn $
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 ((const char *)message != NULL) 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 ((const char *)message != NULL) 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         mos;
00436     int         treat_as_lss = 0;
00437     double      mean_rms;
00438     double      mxpos;
00439     int         narc, nref;
00440     int         nlines;
00441     int         rebin;
00442     double     *line;
00443     double     *fiterror = NULL;
00444     int        *fitlines = NULL;
00445     int         nx, ny;
00446     double      reference;
00447     int         i;
00448     int         nslits_out_det = 0;
00449 
00450 
00451     char       *instrume = NULL;
00452 
00453 
00454     cpl_msg_set_indentation(2);
00455 
00456     /*
00457      * Get configuration parameters
00458      */
00459 
00460     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00461     cpl_msg_indent_more();
00462     
00463     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00464         fors_wave_calib_exit("Too many in input: GRISM_TABLE"); 
00465 
00466     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00467 
00468     dispersion = dfs_get_parameter_double(parlist,
00469                     "fors.fors_wave_calib.dispersion", grism_table);
00470 
00471     if (dispersion <= 0.0)
00472         fors_wave_calib_exit("Invalid spectral dispersion value");
00473 
00474     peakdetection = dfs_get_parameter_double(parlist,
00475                     "fors.fors_wave_calib.peakdetection", grism_table);
00476     if (peakdetection <= 0.0)
00477         fors_wave_calib_exit("Invalid peak detection level");
00478 
00479     wdegree = dfs_get_parameter_int(parlist,
00480                     "fors.fors_wave_calib.wdegree", grism_table);
00481 
00482     if (wdegree < 1)
00483         fors_wave_calib_exit("Invalid polynomial degree");
00484 
00485     if (wdegree > 5)
00486         fors_wave_calib_exit("Max allowed polynomial degree is 5");
00487 
00488     wradius = dfs_get_parameter_int(parlist, 
00489                                     "fors.fors_wave_calib.wradius", NULL);
00490 
00491     if (wradius < 0)
00492         fors_wave_calib_exit("Invalid search radius");
00493 
00494     wreject = dfs_get_parameter_double(parlist, 
00495                                     "fors.fors_wave_calib.wreject", NULL);
00496 
00497     if (wreject <= 0.0)
00498         fors_wave_calib_exit("Invalid rejection threshold");
00499 
00500     wcolumn = dfs_get_parameter_string(parlist, 
00501                                     "fors.fors_wave_calib.wcolumn", NULL);
00502 
00503     startwavelength = dfs_get_parameter_double(parlist,
00504                     "fors.fors_wave_calib.startwavelength", grism_table);
00505     if (startwavelength > 1.0)
00506         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00507             fors_wave_calib_exit("Invalid wavelength");
00508 
00509     endwavelength = dfs_get_parameter_double(parlist,
00510                     "fors.fors_wave_calib.endwavelength", grism_table);
00511     if (endwavelength > 1.0) {
00512         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00513             fors_wave_calib_exit("Invalid wavelength");
00514         if (startwavelength < 1.0)
00515             fors_wave_calib_exit("Invalid wavelength interval");
00516     }
00517 
00518     if (startwavelength > 1.0)
00519         if (endwavelength - startwavelength <= 0.0)
00520             fors_wave_calib_exit("Invalid wavelength interval");
00521 
00522     cpl_table_delete(grism_table); grism_table = NULL;
00523 
00524     if (cpl_error_get_code())
00525         fors_wave_calib_exit("Failure reading the configuration parameters");
00526 
00527 
00528     cpl_msg_indent_less();
00529     cpl_msg_info(recipe, "Check input set-of-frames:");
00530     cpl_msg_indent_more();
00531 
00532     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0)
00533         fors_wave_calib_exit("Missing required input: MASTER_LINECAT");
00534 
00535     if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1)
00536         fors_wave_calib_exit("Too many in input: MASTER_LINECAT");
00537 
00538     lamp_mxu = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MXU");
00539     lamp_mos = cpl_frameset_count_tags(frameset, "RECTIFIED_LAMP_MOS");
00540 
00541     narc = lamp_mxu + lamp_mos;
00542 
00543     if (narc == 0) {
00544         fors_wave_calib_exit("Missing input rectified arc lamp frame");
00545     }
00546     if (narc > 1) {
00547         cpl_msg_error(recipe, "Too many input rectified arc lamp frames "
00548                       "(%d > 1)", narc);
00549         fors_wave_calib_exit(NULL);
00550     }
00551 
00552     mos = 0;
00553 
00554     if (lamp_mxu) {
00555         arc_tag                 = "RECTIFIED_LAMP_MXU";
00556         slit_location_tag       = "SLIT_LOCATION_MXU";
00557         spatial_map_tag         = "SPATIAL_MAP_MXU";
00558         reduced_lamp_tag        = "REDUCED_LAMP_MXU";
00559         disp_residuals_tag      = "DISP_RESIDUALS_MXU";
00560         disp_coeff_tag          = "DISP_COEFF_MXU";
00561         curv_coeff_tag          = "CURV_COEFF_MXU";
00562         wavelength_map_tag      = "WAVELENGTH_MAP_MXU";
00563         spectral_resolution_tag = "SPECTRAL_RESOLUTION_MXU";
00564     }
00565     else if (lamp_mos) {
00566         mos = 1;
00567         arc_tag                 = "RECTIFIED_LAMP_MOS";
00568         slit_location_tag       = "SLIT_LOCATION_MOS";
00569         spatial_map_tag         = "SPATIAL_MAP_MOS";
00570         reduced_lamp_tag        = "REDUCED_LAMP_MOS";
00571         disp_residuals_tag      = "DISP_RESIDUALS_MOS";
00572         disp_coeff_tag          = "DISP_COEFF_MOS";
00573         curv_coeff_tag          = "CURV_COEFF_MXU";
00574         wavelength_map_tag      = "WAVELENGTH_MAP_MOS";
00575         spectral_resolution_tag = "SPECTRAL_RESOLUTION_MOS";
00576     }
00577 
00578 
00579     nref = cpl_frameset_count_tags(frameset, spatial_map_tag);
00580 
00581     if (nref == 0) {
00582         fors_wave_calib_exit("Missing input spatial map");
00583     }
00584     if (nref > 1) {
00585         cpl_msg_error(recipe, "Too many input spatial maps (%d > 1)", nref);
00586         fors_wave_calib_exit(NULL);
00587     }
00588 
00589     nref = cpl_frameset_count_tags(frameset, slit_location_tag);
00590 
00591     if (nref == 0) {
00592         fors_wave_calib_exit("Missing input slit location table");
00593     }
00594     if (nref > 1) {
00595         cpl_msg_error(recipe, "Too many input slit location tables (%d > 1)", 
00596                       nref);
00597         fors_wave_calib_exit(NULL);
00598     }
00599 
00600     nref = cpl_frameset_count_tags(frameset, curv_coeff_tag);
00601 
00602     if (nref == 0) {
00603         fors_wave_calib_exit("Missing input spectral curvature table");
00604     }
00605     if (nref > 1) {
00606         cpl_msg_error(recipe, "Too many input spectral curvature tables "
00607                       "(%d > 1)", nref);
00608         fors_wave_calib_exit(NULL);
00609     }
00610 
00611 
00612     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00613         cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00614 
00615     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00616         cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00617 
00618     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00619         cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00620 
00621 
00622     /*
00623      * Get the reference wavelength and the rebin factor along the
00624      * dispersion direction from the arc lamp exposure
00625      */
00626 
00627     header = dfs_load_header(frameset, spatial_map_tag, 0);
00628 
00629     if (header == NULL)
00630         fors_wave_calib_exit("Cannot load arc lamp header");
00631 
00632     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00633     if (instrume == NULL)
00634         fors_wave_calib_exit("Missing keyword INSTRUME in arc lamp header");
00635 
00636     if (instrume[4] == '1')
00637         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00638     if (instrume[4] == '2')
00639         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00640 
00641     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00642 
00643     if (cpl_error_get_code() != CPL_ERROR_NONE)
00644         fors_wave_calib_exit("Missing keyword ESO INS GRIS1 WLEN "
00645                                  "in arc lamp frame header");
00646 
00647     if (reference < 3000.0)   /* Perhaps in nanometers... */
00648         reference *= 10;
00649 
00650     if (reference < 3000.0 || reference > 13000.0) {
00651         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00652                       "keyword ESO INS GRIS1 WLEN in arc lamp frame header",
00653                       reference);
00654         fors_wave_calib_exit(NULL);
00655     }
00656 
00657     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00658 
00659     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00660 
00661     if (cpl_error_get_code() != CPL_ERROR_NONE)
00662         fors_wave_calib_exit("Missing keyword ESO DET WIN1 BINX "
00663                                  "in arc lamp frame header");
00664 
00665     if (rebin != 1) {
00666         dispersion *= rebin;
00667         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00668                         "working dispersion used is %f A/pixel", rebin,
00669                         dispersion);
00670     }
00671 
00672 
00673     cpl_msg_info(recipe, "Produce mask slit position table...");
00674 
00675     if (mos)
00676         maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00677     else
00678         maskslits = mos_load_slits_fors_mxu(header);
00679 
00680 
00681     /*
00682      * Check if all slits have the same X offset: in such case,
00683      * treat the observation as a long-slit one!
00684      */
00685 
00686     treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
00687 
00688     cpl_table_delete(maskslits); maskslits = NULL;
00689 
00690     if (treat_as_lss) {
00691         cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
00692                       "The LSS data reduction strategy must be applied: "
00693                       "please use recipe fors_wave_calib_lss", mxpos);
00694         fors_wave_calib_exit(NULL);
00695     }
00696 
00697 
00698     cpl_msg_indent_less();
00699     cpl_msg_info(recipe, "Load arc lamp exposure...");
00700     cpl_msg_indent_more();
00701 
00702     spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0);
00703 
00704     if (spectra == NULL)
00705         fors_wave_calib_exit("Cannot load arc lamp exposure");
00706 
00707 
00708     cpl_msg_indent_less();
00709     cpl_msg_info(recipe, "Load input line catalog...");
00710     cpl_msg_indent_more();
00711 
00712     wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1);
00713 
00714     if (wavelengths == NULL)
00715         fors_wave_calib_exit("Cannot load line catalog");
00716 
00717 
00718     /*
00719      * Cast the wavelengths into a (double precision) CPL vector
00720      */
00721 
00722     nlines = cpl_table_get_nrow(wavelengths);
00723 
00724     if (nlines == 0)
00725         fors_wave_calib_exit("Empty input line catalog");
00726 
00727     if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
00728         cpl_msg_error(recipe, "Missing column %s in input line catalog table",
00729                       wcolumn);
00730         fors_wave_calib_exit(NULL);
00731     }
00732 
00733     line = cpl_malloc(nlines * sizeof(double));
00734 
00735     for (i = 0; i < nlines; i++)
00736         line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
00737 
00738     cpl_table_delete(wavelengths); wavelengths = NULL;
00739 
00740     lines = cpl_vector_wrap(nlines, line);
00741 
00742 
00743     cpl_msg_indent_less();
00744     cpl_msg_info(recipe, "Load slit location table...");
00745     cpl_msg_indent_more();
00746 
00747     slits = dfs_load_table(frameset, slit_location_tag, 1);
00748 
00749     if (slits == NULL)
00750         fors_wave_calib_exit("Cannot load slit location table");
00751 
00752 
00753     cpl_msg_indent_less();
00754     cpl_msg_info(recipe, "Subtract background from input arc exposure...");
00755     cpl_msg_indent_more();
00756 
00757     bimage = mos_arc_background(spectra, 15, 15);
00758     cpl_image_subtract(spectra, bimage);
00759     cpl_image_delete(bimage);
00760 
00761 
00762     cpl_msg_indent_less();
00763     cpl_msg_info(recipe, "Perform wavelength calibration...");
00764     cpl_msg_indent_more();
00765 
00766     nx = cpl_image_get_size_x(spectra);
00767     ny = cpl_image_get_size_y(spectra);
00768 
00769     idscoeff = cpl_table_new(ny);
00770     rainbow  = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00771     residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00772     fiterror = cpl_calloc(ny, sizeof(double));
00773     fitlines = cpl_calloc(ny, sizeof(int));
00774 
00775     rectified = mos_wavelength_calibration_final(spectra, slits, lines, 
00776                                                  dispersion, peakdetection,
00777                                                  wradius, wdegree, wreject,
00778                                                  reference, &startwavelength,
00779                                                  &endwavelength, fitlines,
00780                                                  fiterror, idscoeff, rainbow,
00781                                                  residual, NULL, NULL);
00782 
00783     cpl_image_delete(spectra); spectra = NULL;
00784 
00785     if (rectified == NULL)
00786         fors_wave_calib_exit("Wavelength calibration failure");
00787 
00788     save_header = cpl_propertylist_new();
00789     cpl_propertylist_update_double(save_header, "CRPIX1", 1.0);
00790     cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00791     cpl_propertylist_update_double(save_header, "CRVAL1",
00792                                    startwavelength + dispersion/2);
00793     cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00794     /* cpl_propertylist_update_double(save_header, "CDELT1", dispersion);
00795     cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
00796     cpl_propertylist_update_double(save_header, "CD1_1", dispersion);
00797     cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00798     cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00799     cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00800     cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00801     cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00802     cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", 1);
00803 
00804     if (dfs_save_image(frameset, rectified, reduced_lamp_tag, save_header,
00805                        parlist, recipe, version))
00806         fors_wave_calib_exit(NULL);
00807 
00808     cpl_propertylist_delete(save_header); save_header = NULL;
00809     save_header = cpl_propertylist_new();
00810 
00811     cpl_propertylist_update_double(save_header, "CRPIX2", 1.0);
00812     cpl_propertylist_update_double(save_header, "CRVAL2", 1.0);
00813     /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */
00814     cpl_propertylist_update_double(save_header, "CD1_1", 1.0);
00815     cpl_propertylist_update_double(save_header, "CD1_2", 0.0);
00816     cpl_propertylist_update_double(save_header, "CD2_1", 0.0);
00817     cpl_propertylist_update_double(save_header, "CD2_2", 1.0);
00818     cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR");
00819     cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL");
00820 
00821     if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header,
00822                        parlist, recipe, version))
00823         fors_wave_calib_exit(NULL);
00824 
00825     cpl_propertylist_delete(save_header); save_header = NULL;
00826     cpl_image_delete(residual); residual = NULL;
00827 
00828     cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL;
00829     cpl_table_set_column_unit(idscoeff, "error", "pixel");
00830     cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL;
00831 
00832     for (i = 0; i < ny; i++)
00833         if (!cpl_table_is_valid(idscoeff, "c0", i))
00834             cpl_table_set_invalid(idscoeff, "error", i);
00835 
00836     if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL,
00837                        parlist, recipe, version))
00838         fors_wave_calib_exit(NULL);
00839 
00840     mean_rms = mos_distortions_rms(rectified, lines, startwavelength,
00841                                    dispersion, 6, 0);
00842 
00843     cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms);
00844 
00845     mean_rms = cpl_table_get_column_mean(idscoeff, "error");
00846 
00847     cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
00848                  mean_rms, mean_rms * dispersion);
00849 
00850     cpl_table_delete(idscoeff); idscoeff = NULL;
00851 
00852     /*
00853      * Create resolution table
00854      */
00855 
00856     restab = mos_resolution_table(rectified, startwavelength, dispersion,
00857                                   60000, lines);
00858 
00859     cpl_vector_delete(lines); lines = NULL;
00860     cpl_image_delete(rectified); rectified = NULL;
00861 
00862     if (restab) {
00863         cpl_msg_info(recipe, "Mean spectral resolution: %.2f",
00864                    cpl_table_get_column_mean(restab, "resolution"));
00865         cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel",
00866                    cpl_table_get_column_mean(restab, "fwhm") / dispersion,
00867                    cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion);
00868 
00869         if (dfs_save_table(frameset, restab, spectral_resolution_tag, NULL,
00870                            parlist, recipe, version))
00871             fors_wave_calib_exit(NULL);
00872 
00873         cpl_table_delete(restab); restab = NULL;
00874     }
00875     else
00876         fors_wave_calib_exit("Cannot compute the spectral resolution table");
00877 
00878 
00879     cpl_msg_indent_less();
00880     cpl_msg_info(recipe, "Load spatial map image...");
00881     cpl_msg_indent_more();
00882 
00883     spatial = dfs_load_image(frameset, spatial_map_tag, CPL_TYPE_FLOAT, 0, 0);
00884 
00885     if (spatial == NULL)
00886         fors_wave_calib_exit("Cannot load spatial map");
00887 
00888     cpl_msg_indent_less();
00889     cpl_msg_info(recipe, "Load spectral curvature table...");
00890     cpl_msg_indent_more();
00891 
00892     polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00893 
00894     if (polytraces == NULL)
00895         fors_wave_calib_exit("Cannot load spectral curvature table");
00896 
00897     wavemap = mos_map_wavelengths(spatial, rainbow, slits, polytraces,
00898                                   reference, startwavelength, endwavelength,
00899                                   dispersion);
00900 
00901     cpl_image_delete(rainbow); rainbow = NULL;
00902     cpl_image_delete(spatial); spatial = NULL;
00903     cpl_table_delete(slits); slits = NULL;
00904     cpl_table_delete(polytraces); polytraces = NULL;
00905 
00906     if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header,
00907                        parlist, recipe, version))
00908         fors_wave_calib_exit(NULL);
00909 
00910     cpl_image_delete(wavemap); wavemap = NULL;
00911     cpl_propertylist_delete(header); header = NULL;
00912 
00913     return 0;
00914 }

Generated on 12 Feb 2016 for FORS Pipeline Reference Manual by  doxygen 1.6.1