FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_wave_calib_lss.c,v 1.8 2013/02/28 15:16: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/02/28 15:16:58 $ 00024 * $Revision: 1.8 $ 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_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 int nslits_out_det = 0; 00660 00661 /* 00662 * Check if all slits have the same X offset. If not, this is the 00663 * wrong recipe... 00664 */ 00665 00666 if (mos) 00667 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det); 00668 else 00669 maskslits = mos_load_slits_fors_mxu(header); 00670 00671 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det); 00672 00673 cpl_table_delete(maskslits); maskslits = NULL; 00674 00675 if (!treat_as_lss) 00676 fors_wave_calib_lss_exit("Input data are not long-slit data"); 00677 } 00678 00679 00680 cpl_msg_indent_less(); 00681 cpl_msg_info(recipe, "Load arc lamp exposure..."); 00682 cpl_msg_indent_more(); 00683 00684 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0); 00685 00686 if (spectra == NULL) 00687 fors_wave_calib_lss_exit("Cannot load arc lamp exposure"); 00688 00689 00690 cpl_msg_indent_less(); 00691 cpl_msg_info(recipe, "Load input line catalog..."); 00692 cpl_msg_indent_more(); 00693 00694 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1); 00695 00696 if (wavelengths == NULL) 00697 fors_wave_calib_lss_exit("Cannot load line catalog"); 00698 00699 00700 /* 00701 * Cast the wavelengths into a (double precision) CPL vector 00702 */ 00703 00704 nlines = cpl_table_get_nrow(wavelengths); 00705 00706 if (nlines == 0) 00707 fors_wave_calib_lss_exit("Empty input line catalog"); 00708 00709 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 00710 cpl_msg_error(recipe, "Missing column %s in input line catalog table", 00711 wcolumn); 00712 fors_wave_calib_lss_exit(NULL); 00713 } 00714 00715 line = cpl_malloc(nlines * sizeof(double)); 00716 00717 for (i = 0; i < nlines; i++) 00718 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 00719 00720 cpl_table_delete(wavelengths); wavelengths = NULL; 00721 00722 lines = cpl_vector_wrap(nlines, line); 00723 00724 00725 cpl_msg_indent_less(); 00726 cpl_msg_info(recipe, "Perform wavelength calibration..."); 00727 cpl_msg_indent_more(); 00728 00729 nx = cpl_image_get_size_x(spectra); 00730 ny = cpl_image_get_size_y(spectra); 00731 00732 wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00733 idscoeff_all = cpl_table_new(ny); 00734 00735 if (mos_saturation_process(spectra)) 00736 fors_wave_calib_lss_exit("Cannot process saturation"); 00737 00738 if (mos_subtract_background(spectra)) 00739 fors_wave_calib_lss_exit("Cannot subtract the background"); 00740 00741 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion, 00742 peakdetection, wradius, 00743 wdegree, wreject, reference, 00744 &startwavelength, 00745 &endwavelength, NULL, 00746 NULL, idscoeff_all, wavemap, 00747 NULL, NULL, NULL); 00748 00749 if (rectified == NULL) 00750 fors_wave_calib_lss_exit("Wavelength calibration failure."); 00751 00752 cpl_image_delete(rectified); rectified = NULL; 00753 00754 first_row = 0; 00755 while (!cpl_table_is_valid(idscoeff_all, "c0", first_row)) 00756 first_row++; 00757 00758 last_row = ny - 1; 00759 while (!cpl_table_is_valid(idscoeff_all, "c0", last_row)) 00760 last_row--; 00761 00762 ylow = first_row + 1; 00763 yhig = last_row + 1; 00764 00765 dummy = cpl_image_extract(spectra, 1, ylow, nx, yhig); 00766 cpl_image_delete(spectra); spectra = dummy; 00767 00768 ny = cpl_image_get_size_y(spectra); 00769 00770 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00771 00772 fiterror = cpl_calloc(ny, sizeof(double)); 00773 fitlines = cpl_calloc(ny, sizeof(int)); 00774 idscoeff = cpl_table_new(ny); 00775 00776 if (mos_saturation_process(spectra)) 00777 fors_wave_calib_lss_exit("Cannot process saturation"); 00778 00779 if (mos_subtract_background(spectra)) 00780 fors_wave_calib_lss_exit("Cannot subtract the background"); 00781 00782 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion, 00783 peakdetection, wradius, 00784 wdegree, wreject, reference, 00785 &startwavelength, 00786 &endwavelength, fitlines, 00787 fiterror, idscoeff, NULL, 00788 residual, NULL, NULL); 00789 00790 if (rectified == NULL) 00791 fors_wave_calib_lss_exit("Wavelength calibration failure."); 00792 00793 /* 00794 * A dummy slit locations table 00795 */ 00796 00797 slits = cpl_table_new(1); 00798 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT); 00799 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE); 00800 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE); 00801 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE); 00802 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE); 00803 cpl_table_new_column(slits, "position", CPL_TYPE_INT); 00804 cpl_table_new_column(slits, "length", CPL_TYPE_INT); 00805 cpl_table_set_column_unit(slits, "xtop", "pixel"); 00806 cpl_table_set_column_unit(slits, "ytop", "pixel"); 00807 cpl_table_set_column_unit(slits, "xbottom", "pixel"); 00808 cpl_table_set_column_unit(slits, "ybottom", "pixel"); 00809 cpl_table_set_column_unit(slits, "position", "pixel"); 00810 cpl_table_set_column_unit(slits, "length", "pixel"); 00811 cpl_table_set_int(slits, "slit_id", 0, 0); 00812 cpl_table_set_double(slits, "xtop", 0, 0); 00813 cpl_table_set_double(slits, "ytop", 0, last_row); 00814 cpl_table_set_double(slits, "xbottom", 0, 0); 00815 cpl_table_set_double(slits, "ybottom", 0, first_row); 00816 cpl_table_set_int(slits, "position", 0, 0); 00817 cpl_table_set_int(slits, "length", 0, ny); 00818 00819 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 00820 parlist, recipe, version)) 00821 fors_wave_calib_lss_exit(NULL); 00822 00823 cpl_table_delete(slits); slits = NULL; 00824 00825 if (wmode) { 00826 cpl_image_delete(rectified); rectified = NULL; 00827 cpl_image_delete(wavemap); wavemap = NULL; 00828 00829 /* 00830 * Wavemap is intentionally NULL in the next two calls 00831 */ 00832 00833 mos_interpolate_wavecalib(idscoeff, wavemap, wmode, 2); 00834 mos_interpolate_wavecalib(idscoeff_all, wavemap, wmode, 2); 00835 00836 wavemap = mos_map_idscoeff(idscoeff_all, nx, reference, 00837 startwavelength, endwavelength); 00838 rectified = mos_wavelength_calibration(spectra, reference, 00839 startwavelength, 00840 endwavelength, dispersion, 00841 idscoeff, 0); 00842 } 00843 00844 cpl_table_delete(idscoeff_all); idscoeff_all = NULL; 00845 00846 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 00847 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 00848 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 00849 00850 for (i = 0; i < ny; i++) 00851 if (!cpl_table_is_valid(idscoeff, "c0", i)) 00852 cpl_table_set_invalid(idscoeff, "error", i); 00853 00854 cpl_msg_info(recipe, "Valid solutions found: %d out of %d rows", 00855 ny - cpl_table_count_invalid(idscoeff, "c0"), ny); 00856 00857 cpl_image_delete(spectra); spectra = NULL; 00858 00859 mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 00860 dispersion, 6, 0); 00861 00862 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms); 00863 00864 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 00865 00866 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 00867 mean_rms, mean_rms * dispersion); 00868 00869 restab = mos_resolution_table(rectified, startwavelength, dispersion, 00870 60000, lines); 00871 00872 if (restab) { 00873 cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 00874 cpl_table_get_column_mean(restab, "resolution")); 00875 cpl_msg_info(recipe, 00876 "Mean reference lines FWHM: %.2f +/- %.2f pixel", 00877 cpl_table_get_column_mean(restab, "fwhm") / dispersion, 00878 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion); 00879 00880 if (dfs_save_table(frameset, restab, spectral_resolution_tag, 00881 NULL, parlist, recipe, version)) 00882 fors_wave_calib_lss_exit(NULL); 00883 00884 cpl_table_delete(restab); restab = NULL; 00885 00886 } 00887 else 00888 fors_wave_calib_lss_exit("Cannot compute the spectral " 00889 "resolution table"); 00890 00891 cpl_vector_delete(lines); lines = NULL; 00892 00893 00894 /* 00895 * Save rectified arc lamp spectrum to disk 00896 */ 00897 00898 save_header = cpl_propertylist_new(); 00899 cpl_propertylist_update_double(save_header, "CRPIX1", 1.0); 00900 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0); 00901 cpl_propertylist_update_double(save_header, "CRVAL1", 00902 startwavelength + dispersion/2); 00903 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0); 00904 /* cpl_propertylist_update_double(save_header, "CDELT1", dispersion); 00905 cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */ 00906 cpl_propertylist_update_double(save_header, "CD1_1", dispersion); 00907 cpl_propertylist_update_double(save_header, "CD1_2", 0.0); 00908 cpl_propertylist_update_double(save_header, "CD2_1", 0.0); 00909 cpl_propertylist_update_double(save_header, "CD2_2", 1.0); 00910 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR"); 00911 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL"); 00912 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", 1); 00913 00914 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, save_header, 00915 parlist, recipe, version)) 00916 fors_wave_calib_lss_exit(NULL); 00917 00918 cpl_image_delete(rectified); rectified = NULL; 00919 cpl_propertylist_delete(save_header); save_header = NULL; 00920 00921 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL, 00922 parlist, recipe, version)) 00923 fors_wave_calib_lss_exit(NULL); 00924 00925 cpl_table_delete(idscoeff); idscoeff = NULL; 00926 00927 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header, 00928 parlist, recipe, version)) 00929 fors_wave_calib_lss_exit(NULL); 00930 00931 cpl_image_delete(wavemap); wavemap = NULL; 00932 cpl_propertylist_delete(header); header = NULL; 00933 header = cpl_propertylist_new(); 00934 00935 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 00936 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 00937 /* cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 00938 cpl_propertylist_update_double(header, "CD1_1", 1.0); 00939 cpl_propertylist_update_double(header, "CD1_2", 0.0); 00940 cpl_propertylist_update_double(header, "CD2_1", 0.0); 00941 cpl_propertylist_update_double(header, "CD2_2", 1.0); 00942 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 00943 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 00944 00945 if (dfs_save_image(frameset, residual, disp_residuals_tag, header, 00946 parlist, recipe, version)) 00947 fors_wave_calib_lss_exit(NULL); 00948 00949 cpl_image_delete(residual); residual = NULL; 00950 cpl_propertylist_delete(header); header = NULL; 00951 00952 return 0; 00953 }