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