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