FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_calib.c,v 1.28 2013/02/28 15:17:34 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:34 $ 00024 * $Revision: 1.28 $ 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 <string.h> 00034 #include <cpl.h> 00035 #include <moses.h> 00036 #include <fors_stack.h> 00037 #include <fors_dfs.h> 00038 #include <fors_header.h> 00039 00040 #ifdef __cplusplus 00041 extern "C" 00042 #endif 00043 int cpl_plugin_get_info(cpl_pluginlist * list); 00044 00045 static int fors_calib_create(cpl_plugin *); 00046 static int fors_calib_exec(cpl_plugin *); 00047 static int fors_calib_destroy(cpl_plugin *); 00048 static int fors_calib(cpl_parameterlist *, cpl_frameset *); 00049 00050 static char fors_calib_description[] = 00051 "This recipe is used to identify reference lines on LSS, MOS and MXU arc lamp\n" 00052 "exposures, and trace the spectral edges on the corresponding flat field\n" 00053 "exposures. This information is used to determine the spectral extraction\n" 00054 "mask to be applied in the scientific data reduction, performed with the\n" 00055 "recipe fors_science.\n" 00056 "This recipe accepts both FORS1 and FORS2 frames. The input arc lamp and\n" 00057 "flat field exposures are assumed to be obtained quasi-simultaneously, so\n" 00058 "that they would be described by exactly the same instrument distortions.\n" 00059 "A line catalog must be specified, containing the wavelengths of the\n" 00060 "reference arc lamp lines used for the wavelength calibration. A grism\n" 00061 "table (typically depending on the instrument mode, and in particular on\n" 00062 "the grism used) may also be specified: this table contains a default\n" 00063 "recipe parameter setting to control the way spectra are extracted for\n" 00064 "a specific instrument mode, as it is used for automatic run of the\n" 00065 "pipeline on Paranal and in Garching. If this table is specified, it\n" 00066 "will modify the default recipe parameter setting, with the exception of\n" 00067 "those parameters which have been explicitly modified on the command line.\n" 00068 "If a grism table is not specified, the input recipe parameters values\n" 00069 "will always be read from the command line, or from an esorex configuration\n" 00070 "file if present, or from their generic default values (that are rarely\n" 00071 "meaningful). Finally a master bias frame must be input to this recipe.\n" 00072 "In the table below the MXU acronym can be read alternatively as MOS\n" 00073 "and LSS, with the exception of CURV_COEFF_LSS, CURV_TRACES_LSS,\n" 00074 "SPATIAL_MAP_LSS, SPECTRA_DETECTION_LSS, and and SLIT_MAP_LSS, which are\n" 00075 "never created. The products SPECTRA_DETECTION_MXU, SLIT_MAP_MXU, and\n" 00076 "DISP_RESIDUALS_MXU, are just created if the --check parameter is set to\n" 00077 "true. The product GLOBAL_DISTORTION_TABLE is just created if more than 12\n" 00078 "separate spectra are found in the CCD.\n\n" 00079 "Input files:\n\n" 00080 " DO category: Type: Explanation: Required:\n" 00081 " SCREEN_FLAT_MXU Raw Flat field exposures Y\n" 00082 " LAMP_MXU Raw Arc lamp exposure Y\n" 00083 " MASTER_BIAS or BIAS Calib Bias frame Y\n" 00084 " MASTER_LINECAT Calib Line catalog Y\n" 00085 " GRISM_TABLE Calib Grism table .\n\n" 00086 "Output files:\n\n" 00087 " DO category: Data type: Explanation:\n" 00088 " MASTER_SCREEN_FLAT_MXU FITS image Combined (sum) flat field\n" 00089 " MASTER_NORM_FLAT_MXU FITS image Normalised flat field\n" 00090 " MAPPED_SCREEN_FLAT_MXU FITS image Wavelength calibrated flat field\n" 00091 " MAPPED_NORM_FLAT_MXU FITS image Wavelength calibrated normalised flat\n" 00092 " REDUCED_LAMP_MXU FITS image Wavelength calibrated arc spectrum\n" 00093 " DISP_COEFF_MXU FITS table Inverse dispersion coefficients\n" 00094 " DISP_RESIDUALS_MXU FITS image Residuals in wavelength calibration\n" 00095 " DISP_RESIDUALS_TABLE_MXU FITS table Residuals in wavelength calibration\n" 00096 " DELTA_IMAGE_MXU FITS image Offset vs linear wavelength calib\n" 00097 " WAVELENGTH_MAP_MXU FITS image Wavelength for each pixel on CCD\n" 00098 " SPECTRA_DETECTION_MXU FITS image Check for preliminary detection\n" 00099 " SLIT_MAP_MXU FITS image Map of central wavelength on CCD\n" 00100 " CURV_TRACES_MXU FITS table Spectral curvature traces\n" 00101 " CURV_COEFF_MXU FITS table Spectral curvature coefficients\n" 00102 " SPATIAL_MAP_MXU FITS image Spatial position along slit on CCD\n" 00103 " SPECTRAL_RESOLUTION_MXU FITS table Resolution at reference arc lines\n" 00104 " SLIT_LOCATION_MXU FITS table Slits on product frames and CCD\n" 00105 " GLOBAL_DISTORTION_TABLE FITS table Global distortions table\n\n"; 00106 00107 #define fors_calib_exit(message) \ 00108 { \ 00109 if (message != NULL ) cpl_msg_error(recipe, message); \ 00110 cpl_free(instrume); \ 00111 cpl_free(pipefile); \ 00112 cpl_free(fiterror); \ 00113 cpl_free(fitlines); \ 00114 cpl_image_delete(bias); \ 00115 cpl_image_delete(master_bias); \ 00116 cpl_image_delete(coordinate); \ 00117 cpl_image_delete(checkwave); \ 00118 cpl_image_delete(flat); \ 00119 cpl_image_delete(master_flat); \ 00120 cpl_image_delete(added_flat); \ 00121 cpl_image_delete(norm_flat); \ 00122 cpl_image_delete(rainbow); \ 00123 cpl_image_delete(rectified); \ 00124 cpl_image_delete(residual); \ 00125 cpl_image_delete(smo_flat); \ 00126 cpl_image_delete(spatial); \ 00127 cpl_image_delete(spectra); \ 00128 cpl_image_delete(wavemap); \ 00129 cpl_image_delete(delta); \ 00130 cpl_image_delete(rect_flat); \ 00131 cpl_image_delete(rect_nflat); \ 00132 cpl_image_delete(mapped_flat); \ 00133 cpl_image_delete(mapped_nflat); \ 00134 cpl_mask_delete(refmask); \ 00135 cpl_propertylist_delete(header); \ 00136 cpl_propertylist_delete(save_header); \ 00137 cpl_propertylist_delete(qclist); \ 00138 cpl_table_delete(grism_table); \ 00139 cpl_table_delete(idscoeff); \ 00140 cpl_table_delete(idscoeff_all); \ 00141 cpl_table_delete(restable); \ 00142 cpl_table_delete(maskslits); \ 00143 cpl_table_delete(overscans); \ 00144 cpl_table_delete(traces); \ 00145 cpl_table_delete(polytraces); \ 00146 cpl_table_delete(slits); \ 00147 cpl_table_delete(restab); \ 00148 cpl_table_delete(global); \ 00149 cpl_table_delete(wavelengths); \ 00150 cpl_vector_delete(lines); \ 00151 cpl_msg_indent_less(); \ 00152 return -1; \ 00153 } 00154 00155 #define fors_calib_exit_memcheck(message) \ 00156 { \ 00157 if (message !=NULL ) cpl_msg_info(recipe, message); \ 00158 printf("free instrume (%p)\n", instrume); \ 00159 cpl_free(instrume); \ 00160 printf("free pipefile (%p)\n", pipefile); \ 00161 cpl_free(pipefile); \ 00162 printf("free fiterror (%p)\n", fiterror); \ 00163 cpl_free(fiterror); \ 00164 printf("free fitlines (%p)\n", fitlines); \ 00165 cpl_free(fitlines); \ 00166 printf("free bias (%p)\n", bias); \ 00167 cpl_image_delete(bias); \ 00168 printf("free master_bias (%p)\n", master_bias); \ 00169 cpl_image_delete(master_bias); \ 00170 printf("free coordinate (%p)\n", coordinate); \ 00171 cpl_image_delete(coordinate); \ 00172 printf("free checkwave (%p)\n", checkwave); \ 00173 cpl_image_delete(checkwave); \ 00174 printf("free flat (%p)\n", flat); \ 00175 cpl_image_delete(flat); \ 00176 printf("free master_flat (%p)\n", master_flat); \ 00177 cpl_image_delete(master_flat); \ 00178 printf("free norm_flat (%p)\n", norm_flat); \ 00179 cpl_image_delete(norm_flat); \ 00180 printf("free mapped_flat (%p)\n", mapped_flat); \ 00181 cpl_image_delete(mapped_flat); \ 00182 printf("free mapped_nflat (%p)\n", mapped_nflat); \ 00183 cpl_image_delete(mapped_nflat); \ 00184 printf("free rainbow (%p)\n", rainbow); \ 00185 cpl_image_delete(rainbow); \ 00186 printf("free rectified (%p)\n", rectified); \ 00187 cpl_image_delete(rectified); \ 00188 printf("free residual (%p)\n", residual); \ 00189 cpl_image_delete(residual); \ 00190 printf("free smo_flat (%p)\n", smo_flat); \ 00191 cpl_image_delete(smo_flat); \ 00192 printf("free spatial (%p)\n", spatial); \ 00193 cpl_image_delete(spatial); \ 00194 printf("free spectra (%p)\n", spectra); \ 00195 cpl_image_delete(spectra); \ 00196 printf("free wavemap (%p)\n", wavemap); \ 00197 cpl_image_delete(wavemap); \ 00198 printf("free delta (%p)\n", delta); \ 00199 cpl_image_delete(delta); \ 00200 printf("free rect_flat (%p)\n", rect_flat); \ 00201 cpl_image_delete(rect_flat); \ 00202 printf("free rect_nflat (%p)\n", rect_nflat); \ 00203 cpl_image_delete(rect_nflat); \ 00204 printf("free refmask (%p)\n", refmask); \ 00205 cpl_mask_delete(refmask); \ 00206 printf("free header (%p)\n", header); \ 00207 cpl_propertylist_delete(header); \ 00208 printf("free save_header (%p)\n", save_header); \ 00209 cpl_propertylist_delete(save_header); \ 00210 printf("free qclist (%p)\n", qclist); \ 00211 cpl_propertylist_delete(qclist); \ 00212 printf("free grism_table (%p)\n", grism_table); \ 00213 cpl_table_delete(grism_table); \ 00214 printf("free idscoeff (%p)\n", idscoeff); \ 00215 cpl_table_delete(idscoeff); \ 00216 printf("free idscoeff_all (%p)\n", idscoeff_all); \ 00217 cpl_table_delete(idscoeff_all); \ 00218 printf("free restable (%p)\n", restable); \ 00219 cpl_table_delete(restable); \ 00220 printf("free maskslits (%p)\n", maskslits); \ 00221 cpl_table_delete(maskslits); \ 00222 printf("free overscans (%p)\n", overscans); \ 00223 cpl_table_delete(overscans); \ 00224 printf("free traces (%p)\n", traces); \ 00225 cpl_table_delete(traces); \ 00226 printf("free polytraces (%p)\n", polytraces); \ 00227 cpl_table_delete(polytraces); \ 00228 printf("free slits (%p)\n", slits); \ 00229 cpl_table_delete(slits); \ 00230 printf("free restab (%p)\n", restab); \ 00231 cpl_table_delete(restab); \ 00232 printf("free global (%p)\n", global); \ 00233 cpl_table_delete(global); \ 00234 printf("free wavelengths (%p)\n", wavelengths); \ 00235 cpl_table_delete(wavelengths); \ 00236 printf("free lines (%p)\n", lines); \ 00237 cpl_vector_delete(lines); \ 00238 cpl_msg_indent_less(); \ 00239 return 0; \ 00240 } 00241 00242 00254 int cpl_plugin_get_info(cpl_pluginlist *list) 00255 { 00256 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00257 cpl_plugin *plugin = &recipe->interface; 00258 00259 cpl_plugin_init(plugin, 00260 CPL_PLUGIN_API, 00261 FORS_BINARY_VERSION, 00262 CPL_PLUGIN_TYPE_RECIPE, 00263 "fors_calib", 00264 "Determination of the extraction mask", 00265 fors_calib_description, 00266 "Carlo Izzo", 00267 PACKAGE_BUGREPORT, 00268 "This file is currently part of the FORS Instrument Pipeline\n" 00269 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00270 "This program is free software; you can redistribute it and/or modify\n" 00271 "it under the terms of the GNU General Public License as published by\n" 00272 "the Free Software Foundation; either version 2 of the License, or\n" 00273 "(at your option) any later version.\n\n" 00274 "This program is distributed in the hope that it will be useful,\n" 00275 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00276 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00277 "GNU General Public License for more details.\n\n" 00278 "You should have received a copy of the GNU General Public License\n" 00279 "along with this program; if not, write to the Free Software Foundation,\n" 00280 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00281 fors_calib_create, 00282 fors_calib_exec, 00283 fors_calib_destroy); 00284 00285 cpl_pluginlist_append(list, plugin); 00286 00287 return 0; 00288 } 00289 00290 00301 static int fors_calib_create(cpl_plugin *plugin) 00302 { 00303 cpl_recipe *recipe; 00304 cpl_parameter *p; 00305 00306 00307 /* 00308 * Check that the plugin is part of a valid recipe 00309 */ 00310 00311 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00312 recipe = (cpl_recipe *)plugin; 00313 else 00314 return -1; 00315 00316 /* 00317 * Create the parameters list in the cpl_recipe object 00318 */ 00319 00320 recipe->parameters = cpl_parameterlist_new(); 00321 00322 00323 /* 00324 * Dispersion 00325 */ 00326 00327 p = cpl_parameter_new_value("fors.fors_calib.dispersion", 00328 CPL_TYPE_DOUBLE, 00329 "Expected spectral dispersion (Angstrom/pixel)", 00330 "fors.fors_calib", 00331 0.0); 00332 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00333 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00334 cpl_parameterlist_append(recipe->parameters, p); 00335 00336 /* 00337 * Peak detection level 00338 */ 00339 00340 p = cpl_parameter_new_value("fors.fors_calib.peakdetection", 00341 CPL_TYPE_DOUBLE, 00342 "Initial peak detection threshold (ADU)", 00343 "fors.fors_calib", 00344 0.0); 00345 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection"); 00346 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00347 cpl_parameterlist_append(recipe->parameters, p); 00348 00349 /* 00350 * Degree of wavelength calibration polynomial 00351 */ 00352 00353 p = cpl_parameter_new_value("fors.fors_calib.wdegree", 00354 CPL_TYPE_INT, 00355 "Degree of wavelength calibration polynomial", 00356 "fors.fors_calib", 00357 0); 00358 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree"); 00359 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00360 cpl_parameterlist_append(recipe->parameters, p); 00361 00362 /* 00363 * Reference lines search radius 00364 */ 00365 00366 p = cpl_parameter_new_value("fors.fors_calib.wradius", 00367 CPL_TYPE_INT, 00368 "Search radius if iterating pattern-matching " 00369 "with first-guess method", 00370 "fors.fors_calib", 00371 4); 00372 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius"); 00373 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00374 cpl_parameterlist_append(recipe->parameters, p); 00375 00376 /* 00377 * Rejection threshold in dispersion relation polynomial fitting 00378 */ 00379 00380 p = cpl_parameter_new_value("fors.fors_calib.wreject", 00381 CPL_TYPE_DOUBLE, 00382 "Rejection threshold in dispersion " 00383 "relation fit (pixel)", 00384 "fors.fors_calib", 00385 0.7); 00386 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject"); 00387 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00388 cpl_parameterlist_append(recipe->parameters, p); 00389 00390 /* 00391 * Wavelength solution interpolation (for LSS data) 00392 */ 00393 00394 p = cpl_parameter_new_value("fors.fors_calib.wmode", 00395 CPL_TYPE_INT, 00396 "Interpolation mode of wavelength solution " 00397 "applicable to LSS-like data (0 = no " 00398 "interpolation, 1 = fill gaps, 2 = global " 00399 "model)", 00400 "fors.fors_calib", 00401 2); 00402 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wmode"); 00403 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00404 cpl_parameterlist_append(recipe->parameters, p); 00405 00406 /* 00407 * Wavelength solution interpolation (for MOS data) 00408 */ 00409 00410 p = cpl_parameter_new_value("fors.fors_calib.wmosmode", 00411 CPL_TYPE_INT, 00412 "Interpolation mode of wavelength solution " 00413 "(0 = no interpolation, 1 = local (slit) " 00414 "solution, 2 = global model)", 00415 "fors.fors_calib", 00416 0); 00417 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wmosmode"); 00418 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00419 cpl_parameterlist_append(recipe->parameters, p); 00420 00421 /* 00422 * Line catalog table column containing the reference wavelengths 00423 */ 00424 00425 p = cpl_parameter_new_value("fors.fors_calib.wcolumn", 00426 CPL_TYPE_STRING, 00427 "Name of line catalog table column " 00428 "with wavelengths", 00429 "fors.fors_calib", 00430 "WLEN"); 00431 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn"); 00432 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00433 cpl_parameterlist_append(recipe->parameters, p); 00434 00435 /* 00436 * Degree of spectral curvature polynomial 00437 */ 00438 00439 p = cpl_parameter_new_value("fors.fors_calib.cdegree", 00440 CPL_TYPE_INT, 00441 "Degree of spectral curvature polynomial", 00442 "fors.fors_calib", 00443 0); 00444 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree"); 00445 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00446 cpl_parameterlist_append(recipe->parameters, p); 00447 00448 /* 00449 * Curvature solution interpolation (for MOS-like data) 00450 */ 00451 00452 p = cpl_parameter_new_value("fors.fors_calib.cmode", 00453 CPL_TYPE_INT, 00454 "Interpolation mode of curvature solution " 00455 "applicable to MOS-like data (0 = no " 00456 "interpolation, 1 = fill gaps, 2 = global " 00457 "model)", 00458 "fors.fors_calib", 00459 1); 00460 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode"); 00461 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00462 cpl_parameterlist_append(recipe->parameters, p); 00463 00464 /* 00465 * Start wavelength for spectral extraction 00466 */ 00467 00468 p = cpl_parameter_new_value("fors.fors_calib.startwavelength", 00469 CPL_TYPE_DOUBLE, 00470 "Start wavelength in spectral extraction", 00471 "fors.fors_calib", 00472 0.0); 00473 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00474 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00475 cpl_parameterlist_append(recipe->parameters, p); 00476 00477 /* 00478 * End wavelength for spectral extraction 00479 */ 00480 00481 p = cpl_parameter_new_value("fors.fors_calib.endwavelength", 00482 CPL_TYPE_DOUBLE, 00483 "End wavelength in spectral extraction", 00484 "fors.fors_calib", 00485 0.0); 00486 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00487 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00488 cpl_parameterlist_append(recipe->parameters, p); 00489 00490 /* 00491 * Try slit identification 00492 */ 00493 00494 p = cpl_parameter_new_value("fors.fors_calib.slit_ident", 00495 CPL_TYPE_BOOL, 00496 "Attempt slit identification for MOS or MXU", 00497 "fors.fors_calib", 00498 TRUE); 00499 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_ident"); 00500 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00501 cpl_parameterlist_append(recipe->parameters, p); 00502 00503 /* 00504 * Flat field frames stack parameters 00505 */ 00506 00507 fors_stack_define_parameters(recipe->parameters, "fors.fors_calib", 00508 "average"); 00509 00510 /* 00511 * Degree of flat field fitting polynomial along spatial direction 00512 * (used for LSS data) 00513 */ 00514 00515 p = cpl_parameter_new_value("fors.fors_calib.sdegree", 00516 CPL_TYPE_INT, 00517 "Degree of flat field fitting polynomial " 00518 "along spatial direction (used for LSS " 00519 "data only)", 00520 "fors.fors_calib", 00521 4); 00522 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sdegree"); 00523 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00524 cpl_parameterlist_append(recipe->parameters, p); 00525 00526 /* 00527 * Degree of flat field fitting polynomial along dispersion direction 00528 * (used for MOS and MXU data) 00529 */ 00530 00531 p = cpl_parameter_new_value("fors.fors_calib.ddegree", 00532 CPL_TYPE_INT, 00533 "Degree of flat field fitting polynomial " 00534 "along dispersion direction (used for MOS " 00535 "and MXU data only)", 00536 "fors.fors_calib", 00537 -1); 00538 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree"); 00539 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00540 cpl_parameterlist_append(recipe->parameters, p); 00541 00542 /* 00543 * Smooth box radius for flat field along dispersion direction 00544 */ 00545 00546 p = cpl_parameter_new_value("fors.fors_calib.dradius", 00547 CPL_TYPE_INT, 00548 "Smooth box radius for flat field along " 00549 "dispersion direction", 00550 "fors.fors_calib", 00551 10); 00552 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius"); 00553 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00554 cpl_parameterlist_append(recipe->parameters, p); 00555 00556 /* 00557 * Smooth box radius for flat field along spatial direction 00558 * (used for LSS data only) 00559 */ 00560 00561 p = cpl_parameter_new_value("fors.fors_calib.sradius", 00562 CPL_TYPE_INT, 00563 "Smooth box radius for flat field along " 00564 "spatial direction", 00565 "fors.fors_calib", 00566 10); 00567 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sradius"); 00568 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00569 cpl_parameterlist_append(recipe->parameters, p); 00570 00571 /* 00572 * Computation of QC1 parameters 00573 */ 00574 00575 p = cpl_parameter_new_value("fors.fors_calib.qc", 00576 CPL_TYPE_BOOL, 00577 "Compute QC1 parameters", 00578 "fors.fors_calib", 00579 TRUE); 00580 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc"); 00581 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00582 cpl_parameterlist_append(recipe->parameters, p); 00583 00584 /* 00585 * Create check products 00586 */ 00587 00588 p = cpl_parameter_new_value("fors.fors_calib.check", 00589 CPL_TYPE_BOOL, 00590 "Create intermediate products", 00591 "fors.fors_calib", 00592 FALSE); 00593 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check"); 00594 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00595 cpl_parameterlist_append(recipe->parameters, p); 00596 00597 return 0; 00598 } 00599 00600 00609 static int fors_calib_exec(cpl_plugin *plugin) 00610 { 00611 cpl_recipe *recipe; 00612 00613 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00614 recipe = (cpl_recipe *)plugin; 00615 else 00616 return -1; 00617 00618 return fors_calib(recipe->parameters, recipe->frames); 00619 } 00620 00621 00630 static int fors_calib_destroy(cpl_plugin *plugin) 00631 { 00632 cpl_recipe *recipe; 00633 00634 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00635 recipe = (cpl_recipe *)plugin; 00636 else 00637 return -1; 00638 00639 cpl_parameterlist_delete(recipe->parameters); 00640 00641 return 0; 00642 } 00643 00644 00654 static int fors_calib(cpl_parameterlist *parlist, cpl_frameset *frameset) 00655 { 00656 00657 const char *recipe = "fors_calib"; 00658 00659 00660 /* 00661 * Input parameters 00662 */ 00663 00664 double dispersion; 00665 double peakdetection; 00666 int wdegree; 00667 int wradius; 00668 double wreject; 00669 int wmode; 00670 int wmosmode; 00671 const char *wcolumn; 00672 int cdegree; 00673 int cmode; 00674 double startwavelength; 00675 double endwavelength; 00676 int slit_ident; 00677 int sdegree; 00678 int ddegree; 00679 int sradius; 00680 int dradius; 00681 int qc; 00682 int check; 00683 const char *stack_method; 00684 int min_reject; 00685 int max_reject; 00686 double klow; 00687 double khigh; 00688 int kiter; 00689 00690 /* 00691 * CPL objects 00692 */ 00693 00694 cpl_imagelist *biases = NULL; 00695 cpl_image *bias = NULL; 00696 cpl_image *master_bias = NULL; 00697 cpl_image *multi_bias = NULL; 00698 cpl_image *flat = NULL; 00699 cpl_image *master_flat = NULL; 00700 cpl_image *added_flat = NULL; 00701 cpl_image *trace_flat = NULL; 00702 cpl_image *smo_flat = NULL; 00703 cpl_image *norm_flat = NULL; 00704 cpl_image *spectra = NULL; 00705 cpl_image *wavemap = NULL; 00706 cpl_image *delta = NULL; 00707 cpl_image *residual = NULL; 00708 cpl_image *checkwave = NULL; 00709 cpl_image *rectified = NULL; 00710 cpl_image *dummy = NULL; 00711 cpl_image *add_dummy = NULL; 00712 cpl_image *refimage = NULL; 00713 cpl_image *coordinate = NULL; 00714 cpl_image *rainbow = NULL; 00715 cpl_image *spatial = NULL; 00716 cpl_image *rect_flat = NULL; 00717 cpl_image *rect_nflat = NULL; 00718 cpl_image *mapped_flat = NULL; 00719 cpl_image *mapped_nflat = NULL; 00720 00721 cpl_mask *refmask = NULL; 00722 00723 cpl_table *grism_table = NULL; 00724 cpl_table *overscans = NULL; 00725 cpl_table *wavelengths = NULL; 00726 cpl_table *idscoeff = NULL; 00727 cpl_table *idscoeff_all = NULL; 00728 cpl_table *restable = NULL; 00729 cpl_table *slits = NULL; 00730 cpl_table *positions = NULL; 00731 cpl_table *maskslits = NULL; 00732 cpl_table *traces = NULL; 00733 cpl_table *polytraces = NULL; 00734 cpl_table *restab = NULL; 00735 cpl_table *global = NULL; 00736 00737 cpl_vector *lines = NULL; 00738 00739 cpl_propertylist *header = NULL; 00740 cpl_propertylist *save_header = NULL; 00741 cpl_propertylist *qclist = NULL; 00742 00743 /* 00744 * Auxiliary variables 00745 */ 00746 00747 char version[80]; 00748 const char *arc_tag; 00749 const char *flat_tag; 00750 const char *master_screen_flat_tag; 00751 const char *master_norm_flat_tag; 00752 const char *reduced_lamp_tag; 00753 const char *disp_residuals_tag; 00754 const char *disp_coeff_tag; 00755 const char *wavelength_map_tag; 00756 const char *spectra_detection_tag; 00757 const char *spectral_resolution_tag; 00758 const char *slit_map_tag; 00759 const char *curv_traces_tag; 00760 const char *curv_coeff_tag; 00761 const char *spatial_map_tag; 00762 const char *slit_location_tag; 00763 const char *global_distortion_tag = "GLOBAL_DISTORTION_TABLE"; 00764 const char *disp_residuals_table_tag; 00765 const char *delta_image_tag; 00766 const char *mapped_screen_flat_tag; 00767 const char *mapped_norm_flat_tag; 00768 const char *keyname; 00769 int mxu, mos, lss; 00770 int treat_as_lss = 0; 00771 int nslits; 00772 float *data; 00773 double mxpos; 00774 double mean_rms; 00775 double mean_rms_err; 00776 double alltime; 00777 int nflats; 00778 int nbias; 00779 int nlines; 00780 int rebin; 00781 double *line; 00782 double *fiterror = NULL; 00783 int *fitlines = NULL; 00784 cpl_size nx, ny; 00785 double reference; 00786 double gain; 00787 int compute_central_wave; 00788 int ccd_xsize, ccd_ysize; 00789 int i; 00790 00791 char *instrume = NULL; 00792 char *pipefile = NULL; 00793 char *wheel4; 00794 00795 00796 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00797 00798 cpl_msg_set_indentation(2); 00799 00800 if (dfs_files_dont_exist(frameset)) 00801 fors_calib_exit(NULL); 00802 00803 /* 00804 * Get configuration parameters 00805 */ 00806 00807 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00808 cpl_msg_indent_more(); 00809 00810 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00811 fors_calib_exit("Too many in input: GRISM_TABLE"); 00812 00813 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00814 00815 dispersion = dfs_get_parameter_double(parlist, 00816 "fors.fors_calib.dispersion", grism_table); 00817 00818 if (dispersion <= 0.0) 00819 fors_calib_exit("Invalid spectral dispersion value"); 00820 00821 peakdetection = dfs_get_parameter_double(parlist, 00822 "fors.fors_calib.peakdetection", grism_table); 00823 if (peakdetection <= 0.0) 00824 fors_calib_exit("Invalid peak detection level"); 00825 00826 wdegree = dfs_get_parameter_int(parlist, 00827 "fors.fors_calib.wdegree", grism_table); 00828 00829 if (wdegree < 1) 00830 fors_calib_exit("Invalid polynomial degree"); 00831 00832 if (wdegree > 5) 00833 fors_calib_exit("Max allowed polynomial degree is 5"); 00834 00835 wradius = dfs_get_parameter_int(parlist, "fors.fors_calib.wradius", NULL); 00836 00837 if (wradius < 0) 00838 fors_calib_exit("Invalid search radius"); 00839 00840 wreject = dfs_get_parameter_double(parlist, 00841 "fors.fors_calib.wreject", NULL); 00842 00843 if (wreject <= 0.0) 00844 fors_calib_exit("Invalid rejection threshold"); 00845 00846 wmode = dfs_get_parameter_int(parlist, "fors.fors_calib.wmode", NULL); 00847 00848 if (wmode < 0 || wmode > 2) 00849 fors_calib_exit("Invalid wavelength solution interpolation mode"); 00850 00851 wmosmode = dfs_get_parameter_int(parlist, 00852 "fors.fors_calib.wmosmode", NULL); 00853 00854 if (wmosmode < 0 || wmosmode > 2) 00855 fors_calib_exit("Invalid wavelength solution interpolation mode"); 00856 00857 wcolumn = dfs_get_parameter_string(parlist, "fors.fors_calib.wcolumn", 00858 NULL); 00859 00860 cdegree = dfs_get_parameter_int(parlist, "fors.fors_calib.cdegree", 00861 grism_table); 00862 00863 if (cdegree < 1) 00864 fors_calib_exit("Invalid polynomial degree"); 00865 00866 if (cdegree > 5) 00867 fors_calib_exit("Max allowed polynomial degree is 5"); 00868 00869 cmode = dfs_get_parameter_int(parlist, "fors.fors_calib.cmode", NULL); 00870 00871 if (cmode < 0 || cmode > 2) 00872 fors_calib_exit("Invalid curvature solution interpolation mode"); 00873 00874 startwavelength = dfs_get_parameter_double(parlist, 00875 "fors.fors_calib.startwavelength", grism_table); 00876 if (startwavelength > 1.0) 00877 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00878 fors_calib_exit("Invalid wavelength"); 00879 00880 endwavelength = dfs_get_parameter_double(parlist, 00881 "fors.fors_calib.endwavelength", grism_table); 00882 if (endwavelength > 1.0) { 00883 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00884 fors_calib_exit("Invalid wavelength"); 00885 if (startwavelength < 1.0) 00886 fors_calib_exit("Invalid wavelength interval"); 00887 } 00888 00889 if (startwavelength > 1.0) 00890 if (endwavelength - startwavelength <= 0.0) 00891 fors_calib_exit("Invalid wavelength interval"); 00892 00893 slit_ident = dfs_get_parameter_bool(parlist, 00894 "fors.fors_calib.slit_ident", NULL); 00895 00896 stack_method = dfs_get_parameter_string(parlist, 00897 "fors.fors_calib.stack_method", 00898 NULL); 00899 00900 if (strcmp(stack_method, "minmax") == 0) { 00901 min_reject = dfs_get_parameter_int(parlist, 00902 "fors.fors_calib.minrejection", NULL); 00903 if (min_reject < 0) 00904 fors_calib_exit("Invalid number of lower rejections"); 00905 00906 max_reject = dfs_get_parameter_int(parlist, 00907 "fors.fors_calib.maxrejection", NULL); 00908 if (max_reject < 0) 00909 fors_calib_exit("Invalid number of upper rejections"); 00910 } 00911 00912 if (strcmp(stack_method, "ksigma") == 0) { 00913 klow = dfs_get_parameter_double(parlist, 00914 "fors.fors_calib.klow", NULL); 00915 if (klow < 0.1) 00916 fors_calib_exit("Invalid lower K-sigma"); 00917 00918 khigh = dfs_get_parameter_double(parlist, 00919 "fors.fors_calib.khigh", NULL); 00920 if (khigh < 0.1) 00921 fors_calib_exit("Invalid lower K-sigma"); 00922 00923 kiter = dfs_get_parameter_int(parlist, 00924 "fors.fors_calib.kiter", NULL); 00925 if (kiter < 1) 00926 fors_calib_exit("Invalid number of iterations"); 00927 } 00928 00929 sdegree = dfs_get_parameter_int(parlist, "fors.fors_calib.sdegree", NULL); 00930 ddegree = dfs_get_parameter_int(parlist, "fors.fors_calib.ddegree", NULL); 00931 sradius = dfs_get_parameter_int(parlist, "fors.fors_calib.sradius", NULL); 00932 dradius = dfs_get_parameter_int(parlist, "fors.fors_calib.dradius", NULL); 00933 00934 if (sradius < 1 || dradius < 1) 00935 fors_calib_exit("Invalid smoothing box radius"); 00936 00937 qc = dfs_get_parameter_bool(parlist, "fors.fors_calib.qc", NULL); 00938 00939 check = dfs_get_parameter_bool(parlist, "fors.fors_calib.check", NULL); 00940 00941 cpl_table_delete(grism_table); grism_table = NULL; 00942 00943 if (cpl_error_get_code()) 00944 fors_calib_exit("Failure getting the configuration parameters"); 00945 00946 00947 /* 00948 * Check input set-of-frames 00949 */ 00950 00951 cpl_msg_indent_less(); 00952 cpl_msg_info(recipe, "Check input set-of-frames:"); 00953 cpl_msg_indent_more(); 00954 00955 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID")) 00956 fors_calib_exit("Input frames are not from the same grism"); 00957 00958 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID")) 00959 fors_calib_exit("Input frames are not from the same filter"); 00960 00961 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID")) 00962 fors_calib_exit("Input frames are not from the same chip"); 00963 00964 mxu = cpl_frameset_count_tags(frameset, "LAMP_MXU"); 00965 mos = cpl_frameset_count_tags(frameset, "LAMP_MOS"); 00966 lss = cpl_frameset_count_tags(frameset, "LAMP_LSS"); 00967 00968 if (mxu + mos + lss == 0) 00969 fors_calib_exit("Missing input arc lamp frame"); 00970 00971 if (mxu + mos + lss > 1) 00972 fors_calib_exit("Just one input arc lamp frame is allowed"); 00973 00974 if (mxu) { 00975 cpl_msg_info(recipe, "MXU data found"); 00976 arc_tag = "LAMP_MXU"; 00977 flat_tag = "SCREEN_FLAT_MXU"; 00978 master_screen_flat_tag = "MASTER_SCREEN_FLAT_MXU"; 00979 master_norm_flat_tag = "MASTER_NORM_FLAT_MXU"; 00980 reduced_lamp_tag = "REDUCED_LAMP_MXU"; 00981 disp_residuals_tag = "DISP_RESIDUALS_MXU"; 00982 disp_coeff_tag = "DISP_COEFF_MXU"; 00983 wavelength_map_tag = "WAVELENGTH_MAP_MXU"; 00984 spectra_detection_tag = "SPECTRA_DETECTION_MXU"; 00985 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MXU"; 00986 slit_map_tag = "SLIT_MAP_MXU"; 00987 curv_traces_tag = "CURV_TRACES_MXU"; 00988 curv_coeff_tag = "CURV_COEFF_MXU"; 00989 spatial_map_tag = "SPATIAL_MAP_MXU"; 00990 slit_location_tag = "SLIT_LOCATION_MXU"; 00991 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_MXU"; 00992 delta_image_tag = "DELTA_IMAGE_MXU"; 00993 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_MXU"; 00994 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_MXU"; 00995 } 00996 00997 if (lss) { 00998 cpl_msg_info(recipe, "LSS data found"); 00999 arc_tag = "LAMP_LSS"; 01000 flat_tag = "SCREEN_FLAT_LSS"; 01001 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LSS"; 01002 master_norm_flat_tag = "MASTER_NORM_FLAT_LSS"; 01003 reduced_lamp_tag = "REDUCED_LAMP_LSS"; 01004 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LSS"; 01005 disp_residuals_tag = "DISP_RESIDUALS_LSS"; 01006 disp_coeff_tag = "DISP_COEFF_LSS"; 01007 slit_location_tag = "SLIT_LOCATION_LSS"; 01008 wavelength_map_tag = "WAVELENGTH_MAP_LSS"; 01009 slit_map_tag = "SLIT_MAP_LSS"; 01010 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LSS"; 01011 delta_image_tag = "DELTA_IMAGE_LSS"; 01012 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LSS"; 01013 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LSS"; 01014 } 01015 01016 if (mos) { 01017 cpl_msg_info(recipe, "MOS data found"); 01018 arc_tag = "LAMP_MOS"; 01019 flat_tag = "SCREEN_FLAT_MOS"; 01020 master_screen_flat_tag = "MASTER_SCREEN_FLAT_MOS"; 01021 master_norm_flat_tag = "MASTER_NORM_FLAT_MOS"; 01022 reduced_lamp_tag = "REDUCED_LAMP_MOS"; 01023 disp_residuals_tag = "DISP_RESIDUALS_MOS"; 01024 disp_coeff_tag = "DISP_COEFF_MOS"; 01025 wavelength_map_tag = "WAVELENGTH_MAP_MOS"; 01026 spectra_detection_tag = "SPECTRA_DETECTION_MOS"; 01027 spectral_resolution_tag = "SPECTRAL_RESOLUTION_MOS"; 01028 slit_map_tag = "SLIT_MAP_MOS"; 01029 curv_traces_tag = "CURV_TRACES_MOS"; 01030 curv_coeff_tag = "CURV_COEFF_MOS"; 01031 spatial_map_tag = "SPATIAL_MAP_MOS"; 01032 slit_location_tag = "SLIT_LOCATION_MOS"; 01033 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_MOS"; 01034 delta_image_tag = "DELTA_IMAGE_MOS"; 01035 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_MOS"; 01036 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_MOS"; 01037 } 01038 01039 nbias = 0; 01040 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) { 01041 if (cpl_frameset_count_tags(frameset, "BIAS") == 0) 01042 fors_calib_exit("Missing required input: MASTER_BIAS or BIAS"); 01043 nbias = cpl_frameset_count_tags(frameset, "BIAS"); 01044 } 01045 01046 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 01047 fors_calib_exit("Too many in input: MASTER_BIAS"); 01048 01049 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0) 01050 fors_calib_exit("Missing required input: MASTER_LINECAT"); 01051 01052 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1) 01053 fors_calib_exit("Too many in input: MASTER_LINECAT"); 01054 01055 nflats = cpl_frameset_count_tags(frameset, flat_tag); 01056 01057 if (nflats < 1) { 01058 cpl_msg_error(recipe, "Missing required input: %s", flat_tag); 01059 fors_calib_exit(NULL); 01060 } 01061 01062 cpl_msg_indent_less(); 01063 01064 if (nflats > 1) 01065 cpl_msg_info(recipe, "Load %d flat field frames and stack them " 01066 "with method \"%s\"", nflats, stack_method); 01067 else 01068 cpl_msg_info(recipe, "Load flat field exposure..."); 01069 01070 cpl_msg_indent_more(); 01071 01072 header = dfs_load_header(frameset, flat_tag, 0); 01073 01074 if (header == NULL) 01075 fors_calib_exit("Cannot load flat field frame header"); 01076 01077 /* 01078 * Insert here a check on supported filters: 01079 */ 01080 01081 wheel4 = (char *)cpl_propertylist_get_string(header, "ESO INS OPTI9 TYPE"); 01082 if (cpl_error_get_code() != CPL_ERROR_NONE) { 01083 fors_calib_exit("Missing keyword ESO INS OPTI9 TYPE in flat header"); 01084 } 01085 01086 if (strcmp("FILT", wheel4) == 0) { 01087 wheel4 = (char *)cpl_propertylist_get_string(header, 01088 "ESO INS OPTI9 NAME"); 01089 cpl_msg_error(recipe, "Unsupported filter: %s", wheel4); 01090 fors_calib_exit(NULL); 01091 } 01092 01093 alltime = cpl_propertylist_get_double(header, "EXPTIME"); 01094 01095 if (cpl_error_get_code() != CPL_ERROR_NONE) 01096 fors_calib_exit("Missing keyword EXPTIME in flat field frame header"); 01097 01098 cpl_propertylist_delete(header); 01099 01100 for (i = 1; i < nflats; i++) { 01101 01102 header = dfs_load_header(frameset, NULL, 0); 01103 01104 if (header == NULL) 01105 fors_calib_exit("Cannot load flat field frame header"); 01106 01107 alltime += cpl_propertylist_get_double(header, "EXPTIME"); 01108 01109 if (cpl_error_get_code() != CPL_ERROR_NONE) 01110 fors_calib_exit("Missing keyword EXPTIME in flat field " 01111 "frame header"); 01112 01113 cpl_propertylist_delete(header); 01114 01115 } 01116 01117 master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0); 01118 01119 if (master_flat == NULL) 01120 fors_calib_exit("Cannot load flat field"); 01121 01122 if (nflats > 1) { 01123 if (strcmp(stack_method, "average") == 0) { 01124 for (i = 1; i < nflats; i++) { 01125 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01126 if (flat) { 01127 cpl_image_add(master_flat, flat); 01128 cpl_image_delete(flat); flat = NULL; 01129 } 01130 else 01131 fors_calib_exit("Cannot load flat field"); 01132 } 01133 01134 /*** 01135 if (nflats > 1) 01136 cpl_image_divide_scalar(master_flat, nflats); 01137 ***/ 01138 01139 } 01140 else { 01141 cpl_imagelist *flatlist = NULL; 01142 double rflux, flux; 01143 01144 /* 01145 * added_flat is needed for tracing (masters obtained with 01146 * rejections are not suitable for tracing) 01147 */ 01148 01149 added_flat = cpl_image_duplicate(master_flat); 01150 01151 flatlist = cpl_imagelist_new(); 01152 cpl_imagelist_set(flatlist, master_flat, 01153 cpl_imagelist_get_size(flatlist)); 01154 master_flat = NULL; 01155 01156 /* 01157 * Stacking with rejection requires normalization 01158 * at the same flux. We normalise according to mean 01159 * flux. This is equivalent to determining the 01160 * flux ration for each image as the average of the 01161 * flux ratio of all pixels weighted on the actual 01162 * flux of each pixel. 01163 */ 01164 01165 rflux = cpl_image_get_mean(added_flat); 01166 01167 for (i = 1; i < nflats; i++) { 01168 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01169 if (flat) { 01170 cpl_image_add(added_flat, flat); 01171 flux = cpl_image_get_mean(flat); 01172 cpl_image_multiply_scalar(flat, rflux / flux); 01173 cpl_imagelist_set(flatlist, flat, 01174 cpl_imagelist_get_size(flatlist)); 01175 flat = NULL; 01176 } 01177 else { 01178 fors_calib_exit("Cannot load flat field"); 01179 } 01180 } 01181 01182 if (strcmp(stack_method, "median") == 0) { 01183 master_flat = cpl_imagelist_collapse_median_create(flatlist); 01184 } 01185 01186 if (strcmp(stack_method, "minmax") == 0) { 01187 master_flat = cpl_imagelist_collapse_minmax_create(flatlist, 01188 min_reject, 01189 max_reject); 01190 } 01191 01192 if (strcmp(stack_method, "ksigma") == 0) { 01193 master_flat = mos_ksigma_stack(flatlist, 01194 klow, khigh, kiter, NULL); 01195 } 01196 01197 cpl_imagelist_delete(flatlist); 01198 } 01199 } 01200 01201 /* 01202 * Get the reference wavelength and the rebin factor along the 01203 * dispersion direction from the arc lamp exposure 01204 */ 01205 01206 header = dfs_load_header(frameset, arc_tag, 0); 01207 01208 if (header == NULL) 01209 fors_calib_exit("Cannot load arc lamp header"); 01210 01211 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 01212 if (instrume == NULL) 01213 fors_calib_exit("Missing keyword INSTRUME in arc lamp header"); 01214 instrume = cpl_strdup(instrume); 01215 01216 if (instrume[4] == '1') 01217 snprintf(version, 80, "%s/%s", "fors1", VERSION); 01218 if (instrume[4] == '2') 01219 snprintf(version, 80, "%s/%s", "fors2", VERSION); 01220 01221 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 01222 01223 if (cpl_error_get_code() != CPL_ERROR_NONE) 01224 fors_calib_exit("Missing keyword ESO INS GRIS1 WLEN in arc lamp " 01225 "frame header"); 01226 01227 if (reference < 3000.0) /* Perhaps in nanometers... */ 01228 reference *= 10; 01229 01230 if (reference < 3000.0 || reference > 13000.0) { 01231 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 01232 "keyword ESO INS GRIS1 WLEN in arc lamp frame header", 01233 reference); 01234 fors_calib_exit(NULL); 01235 } 01236 01237 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 01238 01239 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 01240 01241 if (cpl_error_get_code() != CPL_ERROR_NONE) 01242 fors_calib_exit("Missing keyword ESO DET WIN1 BINX in arc lamp " 01243 "frame header"); 01244 01245 if (rebin != 1) { 01246 dispersion *= rebin; 01247 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01248 "working dispersion used is %f A/pixel", rebin, 01249 dispersion); 01250 } 01251 01252 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01253 01254 if (cpl_error_get_code() != CPL_ERROR_NONE) 01255 fors_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp " 01256 "frame header"); 01257 01258 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 01259 01260 if (mos || mxu) { 01261 01262 int nslits_out_det = 0; 01263 01264 cpl_msg_info(recipe, "Produce mask slit position table..."); 01265 if (mos) 01266 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det); 01267 else 01268 maskslits = mos_load_slits_fors_mxu(header); 01269 01270 /* 01271 * Check if all slits have the same X offset: in such case, 01272 * treat the observation as a long-slit one! 01273 */ 01274 01275 mxpos = cpl_table_get_column_median(maskslits, "xtop"); 01276 nslits = cpl_table_get_nrow(maskslits); 01277 01278 01279 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det); 01280 01281 if (treat_as_lss) { 01282 cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n" 01283 "The LSS data reduction strategy is applied!", 01284 mxpos); 01285 cpl_table_delete(maskslits); maskslits = NULL; 01286 if (mos) { 01287 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LONG_MOS"; 01288 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MOS"; 01289 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LONG_MOS"; 01290 delta_image_tag = "DELTA_IMAGE_LONG_MOS"; 01291 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LONG_MOS"; 01292 reduced_lamp_tag = "REDUCED_LAMP_LONG_MOS"; 01293 disp_coeff_tag = "DISP_COEFF_LONG_MOS"; 01294 wavelength_map_tag = "WAVELENGTH_MAP_LONG_MOS"; 01295 slit_location_tag = "SLIT_LOCATION_LONG_MOS"; 01296 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LONG_MOS"; 01297 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LONG_MOS"; 01298 } 01299 else { 01300 master_screen_flat_tag = "MASTER_SCREEN_FLAT_LONG_MXU"; 01301 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MXU"; 01302 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_LONG_MXU"; 01303 delta_image_tag = "DELTA_IMAGE_LONG_MXU"; 01304 spectral_resolution_tag = "SPECTRAL_RESOLUTION_LONG_MXU"; 01305 reduced_lamp_tag = "REDUCED_LAMP_LONG_MXU"; 01306 disp_coeff_tag = "DISP_COEFF_LONG_MXU"; 01307 wavelength_map_tag = "WAVELENGTH_MAP_LONG_MXU"; 01308 slit_location_tag = "SLIT_LOCATION_LONG_MXU"; 01309 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_LONG_MXU"; 01310 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_LONG_MXU"; 01311 } 01312 } 01313 } 01314 01315 if (slit_ident == 0) { 01316 cpl_table_delete(maskslits); maskslits = NULL; 01317 } 01318 01319 01320 /* Leave the header on for the next step... */ 01321 01322 01323 /* 01324 * Remove the master bias 01325 */ 01326 01327 if (nbias) { 01328 01329 /* 01330 * Set of raw BIASes in input, need to create master bias! 01331 */ 01332 01333 cpl_msg_info(recipe, "Generate the master from input raw biases..."); 01334 01335 if (nbias > 1) { 01336 01337 biases = cpl_imagelist_new(); 01338 01339 bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0); 01340 01341 if (bias == NULL) 01342 fors_calib_exit("Cannot load bias frame"); 01343 01344 cpl_imagelist_set(biases, bias, 0); bias = NULL; 01345 01346 for (i = 1; i < nbias; i++) { 01347 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01348 if (bias) { 01349 cpl_imagelist_set(biases, bias, i); bias = NULL; 01350 } 01351 else 01352 fors_calib_exit("Cannot load bias frame"); 01353 } 01354 01355 master_bias = cpl_imagelist_collapse_median_create(biases); 01356 01357 cpl_imagelist_delete(biases); 01358 } 01359 else { 01360 master_bias = dfs_load_image(frameset, "BIAS", 01361 CPL_TYPE_FLOAT, 0, 1); 01362 if (master_bias == NULL) 01363 fors_calib_exit("Cannot load bias"); 01364 } 01365 01366 } 01367 else { 01368 master_bias = dfs_load_image(frameset, "MASTER_BIAS", 01369 CPL_TYPE_FLOAT, 0, 1); 01370 if (master_bias == NULL) 01371 fors_calib_exit("Cannot load master bias"); 01372 } 01373 01374 cpl_msg_info(recipe, "Remove the master bias..."); 01375 01376 overscans = mos_load_overscans_vimos(header, 1); 01377 cpl_propertylist_delete(header); header = NULL; 01378 01379 if (nbias) { 01380 int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL); 01381 int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL); 01382 int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL); 01383 int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL); 01384 dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig); 01385 cpl_image_delete(master_bias); master_bias = dummy; 01386 01387 if (dfs_save_image(frameset, master_bias, "MASTER_BIAS", 01388 NULL, parlist, recipe, version)) 01389 fors_calib_exit(NULL); 01390 } 01391 01392 if (nflats > 1) { 01393 multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats); 01394 dummy = mos_remove_bias(master_flat, multi_bias, overscans); 01395 if (added_flat) 01396 add_dummy = mos_remove_bias(added_flat, multi_bias, overscans); 01397 cpl_image_delete(multi_bias); 01398 } 01399 else { 01400 dummy = mos_remove_bias(master_flat, master_bias, overscans); 01401 } 01402 cpl_image_delete(master_flat); 01403 master_flat = dummy; 01404 01405 if (master_flat == NULL) 01406 fors_calib_exit("Cannot remove bias from flat field"); 01407 01408 if (added_flat) { 01409 cpl_image_delete(added_flat); 01410 added_flat = add_dummy; 01411 01412 if (added_flat == NULL) 01413 fors_calib_exit("Cannot remove bias from added flat field"); 01414 01415 trace_flat = added_flat; 01416 } 01417 else 01418 trace_flat = master_flat; 01419 01420 cpl_msg_indent_less(); 01421 cpl_msg_info(recipe, "Load arc lamp exposure..."); 01422 cpl_msg_indent_more(); 01423 01424 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0); 01425 01426 if (spectra == NULL) 01427 fors_calib_exit("Cannot load arc lamp exposure"); 01428 01429 cpl_msg_info(recipe, "Remove the master bias..."); 01430 01431 dummy = mos_remove_bias(spectra, master_bias, overscans); 01432 cpl_table_delete(overscans); overscans = NULL; 01433 cpl_image_delete(master_bias); master_bias = NULL; 01434 cpl_image_delete(spectra); spectra = dummy; 01435 01436 if (spectra == NULL) 01437 fors_calib_exit("Cannot remove bias from arc lamp exposure"); 01438 01439 cpl_msg_indent_less(); 01440 cpl_msg_info(recipe, "Load input line catalog..."); 01441 cpl_msg_indent_more(); 01442 01443 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1); 01444 01445 if (wavelengths == NULL) 01446 fors_calib_exit("Cannot load line catalog"); 01447 01448 01449 /* 01450 * Cast the wavelengths into a (double precision) CPL vector 01451 */ 01452 01453 nlines = cpl_table_get_nrow(wavelengths); 01454 01455 if (nlines == 0) 01456 fors_calib_exit("Empty input line catalog"); 01457 01458 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 01459 cpl_msg_error(recipe, "Missing column %s in input line catalog table", 01460 wcolumn); 01461 fors_calib_exit(NULL); 01462 } 01463 01464 line = cpl_malloc(nlines * sizeof(double)); 01465 01466 for (i = 0; i < nlines; i++) 01467 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 01468 01469 cpl_table_delete(wavelengths); wavelengths = NULL; 01470 01471 lines = cpl_vector_wrap(nlines, line); 01472 01473 01474 if (lss || treat_as_lss) { 01475 01476 cpl_size first_row, last_row; 01477 cpl_size ylow, yhig; 01478 01479 /* FIXME: 01480 * The LSS data calibration is still dirty: it doesn't apply 01481 * any spatial rectification, and only in future an external 01482 * spectral curvature model would be provided in input. Here 01483 * and there temporary solutions are adpted, such as accepting 01484 * the preliminary wavelength calibration. 01485 */ 01486 01487 /* 01488 * Flat field normalisation is done directly on the master flat 01489 * field (without spatial rectification first). The spectral 01490 * curvature model may be provided in input, in future releases. 01491 */ 01492 01493 cpl_msg_indent_less(); 01494 cpl_msg_info(recipe, "Perform LSS flat field normalisation..."); 01495 cpl_msg_indent_more(); 01496 01497 norm_flat = cpl_image_duplicate(master_flat); 01498 01499 smo_flat = mos_normalise_longflat(norm_flat, sradius, dradius, 01500 sdegree); 01501 01502 cpl_image_delete(smo_flat); smo_flat = NULL; /* It may be a product */ 01503 01504 if (1) { 01505 save_header = dfs_load_header(frameset, flat_tag, 0); 01506 cpl_propertylist_update_int(save_header, 01507 "ESO PRO DATANCOM", nflats); 01508 01509 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag, 01510 save_header, parlist, recipe, version)) 01511 fors_calib_exit(NULL); 01512 //%%%%% cpl_image_delete(master_flat); master_flat = NULL; 01513 } 01514 01515 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag, 01516 save_header, parlist, recipe, version)) 01517 fors_calib_exit(NULL); 01518 01519 cpl_propertylist_delete(save_header); save_header = NULL; 01520 //%%%%% cpl_image_delete(norm_flat); norm_flat = NULL; 01521 01522 01523 /* 01524 * In the case of LSS data, extract the spectra directly 01525 * on the first attempt. The spectral curvature model may 01526 * be provided in input, in future releases. 01527 */ 01528 01529 cpl_msg_indent_less(); 01530 cpl_msg_info(recipe, "Perform wavelength calibration..."); 01531 cpl_msg_indent_more(); 01532 01533 nx = cpl_image_get_size_x(spectra); 01534 ny = cpl_image_get_size_y(spectra); 01535 01536 wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01537 idscoeff_all = cpl_table_new(ny); 01538 01539 if (mos_saturation_process(spectra)) 01540 fors_calib_exit("Cannot process saturation"); 01541 01542 if (mos_subtract_background(spectra)) 01543 fors_calib_exit("Cannot subtract the background"); 01544 01545 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion, 01546 peakdetection, wradius, 01547 wdegree, wreject, reference, 01548 &startwavelength, 01549 &endwavelength, NULL, 01550 NULL, idscoeff_all, wavemap, 01551 NULL, NULL, NULL); 01552 01553 if (rectified == NULL) 01554 fors_calib_exit("Wavelength calibration failure."); 01555 01556 if (!cpl_table_has_valid(idscoeff_all, "c0")) 01557 fors_calib_exit("Wavelength calibration failure."); 01558 01559 cpl_image_delete(rectified); rectified = NULL; 01560 01561 first_row = 0; 01562 while (!cpl_table_is_valid(idscoeff_all, "c0", first_row)) 01563 first_row++; 01564 01565 last_row = ny - 1; 01566 while (!cpl_table_is_valid(idscoeff_all, "c0", last_row)) 01567 last_row--; 01568 01569 ylow = first_row + 1; 01570 yhig = last_row + 1; 01571 01572 if (ylow >= yhig) { 01573 cpl_error_reset(); 01574 fors_calib_exit("No spectra could be detected."); 01575 } 01576 01577 cpl_msg_info(recipe, 01578 "Spectral pattern was detected on %"CPL_SIZE_FORMAT 01579 " out of %"CPL_SIZE_FORMAT" CCD rows", 01580 yhig - ylow, ny); 01581 01582 dummy = cpl_image_extract(spectra, 1, ylow, nx, yhig); 01583 cpl_image_delete(spectra); spectra = dummy; 01584 01585 ccd_ysize = (int)ny; 01586 ny = cpl_image_get_size_y(spectra); 01587 01588 if (check) 01589 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01590 01591 fiterror = cpl_calloc(ny, sizeof(double)); 01592 fitlines = cpl_calloc(ny, sizeof(int)); 01593 idscoeff = cpl_table_new(ny); 01594 restable = cpl_table_new(nlines); 01595 01596 if (mos_saturation_process(spectra)) 01597 fors_calib_exit("Cannot process saturation"); 01598 01599 if (mos_subtract_background(spectra)) 01600 fors_calib_exit("Cannot subtract the background"); 01601 01602 rectified = mos_wavelength_calibration_raw(spectra, lines, dispersion, 01603 peakdetection, wradius, 01604 wdegree, wreject, reference, 01605 &startwavelength, 01606 &endwavelength, fitlines, 01607 fiterror, idscoeff, NULL, 01608 residual, restable, NULL); 01609 01610 if (rectified == NULL) 01611 fors_calib_exit("Wavelength calibration failure."); 01612 01613 if (!cpl_table_has_valid(idscoeff, "c0")) 01614 fors_calib_exit("Wavelength calibration failure."); 01615 01616 /* 01617 * A dummy slit locations table 01618 */ 01619 01620 slits = cpl_table_new(1); 01621 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT); 01622 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE); 01623 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE); 01624 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE); 01625 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE); 01626 cpl_table_new_column(slits, "position", CPL_TYPE_INT); 01627 cpl_table_new_column(slits, "length", CPL_TYPE_INT); 01628 cpl_table_set_column_unit(slits, "xtop", "pixel"); 01629 cpl_table_set_column_unit(slits, "ytop", "pixel"); 01630 cpl_table_set_column_unit(slits, "xbottom", "pixel"); 01631 cpl_table_set_column_unit(slits, "ybottom", "pixel"); 01632 cpl_table_set_column_unit(slits, "position", "pixel"); 01633 cpl_table_set_column_unit(slits, "length", "pixel"); 01634 cpl_table_set_int(slits, "slit_id", 0, 0); 01635 cpl_table_set_double(slits, "xtop", 0, 0); 01636 cpl_table_set_double(slits, "ytop", 0, (double)last_row); 01637 cpl_table_set_double(slits, "xbottom", 0, 0); 01638 cpl_table_set_double(slits, "ybottom", 0, (double)first_row); 01639 cpl_table_set_int(slits, "position", 0, 0); 01640 cpl_table_set_int(slits, "length", 0, (int)ny); 01641 01642 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 01643 parlist, recipe, version)) 01644 fors_calib_exit(NULL); 01645 01646 cpl_table_delete(slits); slits = NULL; 01647 01648 if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL, 01649 parlist, recipe, version)) 01650 fors_calib_exit(NULL); 01651 01652 cpl_table_delete(restable); restable = NULL; 01653 01654 if (wmode) { 01655 cpl_image_delete(rectified); rectified = NULL; 01656 cpl_image_delete(wavemap); wavemap = NULL; 01657 mos_interpolate_wavecalib(idscoeff, wavemap, wmode, 2); 01658 mos_interpolate_wavecalib(idscoeff_all, wavemap, wmode, 2); 01659 wavemap = mos_map_idscoeff(idscoeff_all, nx, reference, 01660 startwavelength, endwavelength); 01661 rectified = mos_wavelength_calibration(spectra, reference, 01662 startwavelength, 01663 endwavelength, dispersion, 01664 idscoeff, 0); 01665 } 01666 01667 cpl_table_delete(idscoeff_all); idscoeff_all = NULL; 01668 01669 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 01670 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 01671 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 01672 01673 for (i = 0; i < ny; i++) 01674 if (!cpl_table_is_valid(idscoeff, "c0", i)) 01675 cpl_table_set_invalid(idscoeff, "error", i); 01676 01677 delta = mos_map_pixel(idscoeff, reference, startwavelength, 01678 endwavelength, dispersion, 2); 01679 01680 //%%%%% 01681 dummy = cpl_image_extract(master_flat, 1, ylow, nx, yhig); 01682 cpl_image_delete(master_flat); master_flat = dummy; 01683 01684 mapped_flat = mos_wavelength_calibration(master_flat, reference, 01685 startwavelength, endwavelength, 01686 dispersion, idscoeff, 0); 01687 01688 cpl_image_delete(master_flat); master_flat = NULL; 01689 01690 dummy = cpl_image_extract(norm_flat, 1, ylow, nx, yhig); 01691 cpl_image_delete(norm_flat); norm_flat = dummy; 01692 01693 mapped_nflat = mos_wavelength_calibration(norm_flat, reference, 01694 startwavelength, endwavelength, 01695 dispersion, idscoeff, 0); 01696 01697 cpl_image_delete(norm_flat); norm_flat = NULL; 01698 01699 header = cpl_propertylist_new(); 01700 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01701 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01702 cpl_propertylist_update_double(header, "CRVAL1", 01703 startwavelength + dispersion/2); 01704 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01705 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01706 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01707 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01708 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01709 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01710 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01711 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01712 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01713 01714 if (dfs_save_image(frameset, delta, delta_image_tag, 01715 header, parlist, recipe, version)) 01716 fors_calib_exit(NULL); 01717 01718 cpl_image_delete(delta); delta = NULL; 01719 01720 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag, 01721 header, parlist, recipe, version)) 01722 fors_calib_exit(NULL); 01723 01724 cpl_image_delete(mapped_flat); mapped_flat = NULL; 01725 01726 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag, 01727 header, parlist, recipe, version)) 01728 fors_calib_exit(NULL); 01729 01730 cpl_image_delete(mapped_nflat); mapped_nflat = NULL; 01731 01732 cpl_propertylist_delete(header); header = NULL; 01733 01734 cpl_msg_info(recipe, "Valid solutions found: %"CPL_SIZE_FORMAT" out of %"CPL_SIZE_FORMAT" rows", 01735 ny - cpl_table_count_invalid(idscoeff, "c0"), ny); 01736 01737 cpl_image_delete(spectra); spectra = NULL; 01738 01739 mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 01740 dispersion, 6, 0); 01741 01742 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms); 01743 01744 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01745 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error"); 01746 01747 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 01748 mean_rms, mean_rms * dispersion); 01749 01750 restab = mos_resolution_table(rectified, startwavelength, dispersion, 01751 60000, lines); 01752 01753 if (restab) { 01754 cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 01755 cpl_table_get_column_mean(restab, "resolution")); 01756 cpl_msg_info(recipe, 01757 "Mean reference lines FWHM: %.2f +/- %.2f pixel", 01758 cpl_table_get_column_mean(restab, "fwhm") / dispersion, 01759 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion); 01760 01761 if (qc) { 01762 01763 header = dfs_load_header(frameset, arc_tag, 0); 01764 01765 if (header == NULL) 01766 fors_calib_exit("Cannot reload arc lamp header"); 01767 01768 qclist = cpl_propertylist_new(); 01769 01770 01771 /* 01772 * QC1 parameters 01773 */ 01774 keyname = "QC.DID"; 01775 01776 if (fors_header_write_string(qclist, 01777 keyname, 01778 "2.0", 01779 "QC1 dictionary")) { 01780 fors_calib_exit("Cannot write dictionary version " 01781 "to QC log file"); 01782 } 01783 01784 if (mos) 01785 keyname = "QC.MOS.RESOLUTION"; 01786 else 01787 keyname = "QC.LSS.RESOLUTION"; 01788 01789 if (fors_header_write_double(qclist, 01790 cpl_table_get_column_mean(restab, 01791 "resolution"), 01792 keyname, NULL, 01793 "Mean spectral resolution")) { 01794 fors_calib_exit("Cannot write mean spectral resolution to " 01795 "QC log file"); 01796 } 01797 01798 if (mos) 01799 keyname = "QC.MOS.RESOLUTION.RMS"; 01800 else 01801 keyname = "QC.LSS.RESOLUTION.RMS"; 01802 01803 if (fors_header_write_double(qclist, 01804 cpl_table_get_column_stdev(restab, 01805 "resolution"), 01806 keyname, NULL, 01807 "Scatter of spectral resolution")) { 01808 fors_calib_exit("Cannot write spectral resolution scatter " 01809 "to QC log file"); 01810 } 01811 01812 if (mos) 01813 keyname = "QC.MOS.RESOLUTION.NWAVE"; 01814 else 01815 keyname = "QC.LSS.RESOLUTION.NWAVE"; 01816 01817 if (fors_header_write_int(qclist, cpl_table_get_nrow(restab) - 01818 cpl_table_count_invalid(restab, 01819 "resolution"), 01820 keyname, NULL, 01821 "Number of examined wavelengths " 01822 "for resolution computation")) { 01823 fors_calib_exit("Cannot write number of lines used in " 01824 "spectral resolution computation " 01825 "to QC log file"); 01826 } 01827 01828 if (mos) 01829 keyname = "QC.MOS.RESOLUTION.MEANRMS"; 01830 else 01831 keyname = "QC.LSS.RESOLUTION.MEANRMS"; 01832 01833 if (fors_header_write_double(qclist, 01834 cpl_table_get_column_mean(restab, 01835 "resolution_rms"), 01836 keyname, NULL, 01837 "Mean error on spectral " 01838 "resolution computation")) { 01839 fors_calib_exit("Cannot write mean error in " 01840 "spectral resolution computation " 01841 "to QC log file"); 01842 } 01843 01844 if (mos) 01845 keyname = "QC.MOS.RESOLUTION.NLINES"; 01846 else 01847 keyname = "QC.LSS.RESOLUTION.NLINES"; 01848 01849 if (fors_header_write_int(qclist, 01850 cpl_table_get_column_mean(restab, "nlines") * 01851 cpl_table_get_nrow(restab), 01852 keyname, NULL, 01853 "Number of lines for spectral " 01854 "resolution computation")) { 01855 fors_calib_exit("Cannot write number of examined " 01856 "wavelengths in spectral resolution computation " 01857 "to QC log file"); 01858 } 01859 01860 // fors_qc_end_group(); 01861 01862 } /* End of QC1 computation */ 01863 01864 if (dfs_save_table(frameset, restab, spectral_resolution_tag, 01865 qclist, parlist, recipe, version)) 01866 fors_calib_exit(NULL); 01867 01868 cpl_table_delete(restab); restab = NULL; 01869 cpl_propertylist_delete(qclist); qclist = NULL; 01870 01871 } 01872 else 01873 fors_calib_exit("Cannot compute the spectral resolution table"); 01874 01875 cpl_vector_delete(lines); lines = NULL; 01876 01877 01878 /* 01879 * Save rectified arc lamp spectrum to disk 01880 */ 01881 01882 header = cpl_propertylist_new(); 01883 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01884 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01885 cpl_propertylist_update_double(header, "CRVAL1", 01886 startwavelength + dispersion/2); 01887 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01888 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01889 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01890 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01891 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01892 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01893 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01894 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01895 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01896 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1); 01897 01898 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header, 01899 parlist, recipe, version)) 01900 fors_calib_exit(NULL); 01901 01902 cpl_image_delete(rectified); rectified = NULL; 01903 cpl_propertylist_delete(header); header = NULL; 01904 01905 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL, 01906 parlist, recipe, version)) 01907 fors_calib_exit(NULL); 01908 01909 cpl_table_delete(idscoeff); idscoeff = NULL; 01910 01911 header = dfs_load_header(frameset, arc_tag, 0); 01912 01913 if (header == NULL) 01914 fors_calib_exit("Cannot reload arc lamp header"); 01915 01916 if (qc) { 01917 01918 compute_central_wave = 0; 01919 if (lss) { 01920 /*** 01921 if (fabs(1.0 - cpl_propertylist_get_double(header, 01922 "ESO INS SLIT WID")) < 0.05) 01923 ***/ 01924 compute_central_wave = 1; 01925 } 01926 else { 01927 if (fabs(mxpos) < 0.05) 01928 compute_central_wave = 1; 01929 } 01930 01931 /* 01932 * QC1 parameters 01933 */ 01934 keyname = "QC.DID"; 01935 01936 if (fors_header_write_string(header, 01937 keyname, 01938 "2.0", 01939 "QC1 dictionary")) { 01940 fors_calib_exit("Cannot write dictionary version " 01941 "to QC log file"); 01942 } 01943 01944 if (fors_header_write_double(header, 01945 mean_rms, 01946 "QC.WAVE.ACCURACY", 01947 "pixel", 01948 "Mean accuracy of wavecalib model")) { 01949 fors_calib_exit("Cannot write mean wavelength calibration " 01950 "accuracy to QC log file"); 01951 } 01952 01953 if (fors_header_write_double(header, 01954 mean_rms_err, 01955 "QC.WAVE.ACCURACY.ERROR", 01956 "pixel", 01957 "Error on accuracy of wavecalib model")) { 01958 fors_calib_exit("Cannot write error on wavelength calibration " 01959 "accuracy to QC log file"); 01960 } 01961 01962 if (compute_central_wave) { 01963 01964 data = cpl_image_get_data(wavemap); 01965 01966 if (lss) { 01967 if (fors_header_write_double(header, 01968 data[nx/2 + ccd_ysize*nx/2], 01969 "QC.LSS.CENTRAL.WAVELENGTH", 01970 "Angstrom", 01971 "Wavelength at CCD center")) { 01972 fors_calib_exit("Cannot write central wavelength to QC " 01973 "log file"); 01974 } 01975 } 01976 else { 01977 if (fors_header_write_double(header, 01978 data[nx/2 + ccd_ysize*nx/2], 01979 "QC.MOS.CENTRAL.WAVELENGTH", 01980 "Angstrom", 01981 "Wavelength at CCD center")) { 01982 fors_calib_exit("Cannot write central wavelength to QC " 01983 "log file"); 01984 } 01985 } 01986 } 01987 } 01988 01989 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, header, 01990 parlist, recipe, version)) 01991 fors_calib_exit(NULL); 01992 01993 cpl_image_delete(wavemap); wavemap = NULL; 01994 01995 cpl_propertylist_erase_regexp(header, "^ESO QC ", 0); 01996 01997 if (check) { 01998 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01999 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02000 /* cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02001 cpl_propertylist_update_double(header, "CD1_1", 1.0); 02002 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02003 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02004 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02005 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02006 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02007 02008 if (dfs_save_image(frameset, residual, disp_residuals_tag, header, 02009 parlist, recipe, version)) 02010 fors_calib_exit(NULL); 02011 02012 cpl_image_delete(residual); residual = NULL; 02013 } 02014 02015 cpl_propertylist_delete(header); header = NULL; 02016 cpl_free(instrume); instrume = NULL; 02017 02018 return 0; /* Successful LSS data reduction */ 02019 02020 } /* End of LSS data reduction section */ 02021 02022 02023 /* 02024 * Here the MOS and MXU calibration is carried out. 02025 */ 02026 02027 /* 02028 * Detecting spectra on the CCD 02029 */ 02030 02031 cpl_msg_indent_less(); 02032 cpl_msg_info(recipe, "Detecting spectra on CCD..."); 02033 cpl_msg_indent_more(); 02034 02035 ccd_xsize = nx = cpl_image_get_size_x(spectra); 02036 ccd_ysize = ny = cpl_image_get_size_y(spectra); 02037 02038 refmask = cpl_mask_new(nx, ny); 02039 02040 if (mos_saturation_process(spectra)) 02041 fors_calib_exit("Cannot process saturation"); 02042 02043 if (mos_subtract_background(spectra)) 02044 fors_calib_exit("Cannot subtract the background"); 02045 02046 checkwave = mos_wavelength_calibration_raw(spectra, lines, dispersion, 02047 peakdetection, wradius, 02048 wdegree, wreject, reference, 02049 &startwavelength, &endwavelength, 02050 NULL, NULL, NULL, NULL, NULL, 02051 NULL, refmask); 02052 02053 if (checkwave == NULL) 02054 fors_calib_exit("Wavelength calibration failure."); 02055 02056 /* 02057 * Save check image to disk 02058 */ 02059 02060 header = cpl_propertylist_new(); 02061 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 02062 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 02063 cpl_propertylist_update_double(header, "CRVAL1", 02064 startwavelength + dispersion/2); 02065 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02066 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02067 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02068 cpl_propertylist_update_double(header, "CD1_1", dispersion); 02069 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02070 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02071 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02072 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02073 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02074 02075 if (check) { 02076 if (dfs_save_image(frameset, checkwave, spectra_detection_tag, header, 02077 parlist, recipe, version)) 02078 fors_calib_exit(NULL); 02079 } 02080 02081 cpl_image_delete(checkwave); checkwave = NULL; 02082 cpl_propertylist_delete(header); header = NULL; 02083 02084 cpl_msg_info(recipe, "Locate slits at reference wavelength on CCD..."); 02085 slits = mos_locate_spectra(refmask); 02086 02087 if (!slits) { 02088 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 02089 fors_calib_exit("No slits could be detected!"); 02090 } 02091 02092 refimage = cpl_image_new_from_mask(refmask); 02093 cpl_mask_delete(refmask); refmask = NULL; 02094 02095 if (check) { 02096 save_header = dfs_load_header(frameset, arc_tag, 0); 02097 if (dfs_save_image(frameset, refimage, slit_map_tag, save_header, 02098 parlist, recipe, version)) 02099 fors_calib_exit(NULL); 02100 cpl_propertylist_delete(save_header); save_header = NULL; 02101 } 02102 02103 cpl_image_delete(refimage); refimage = NULL; 02104 02105 if (slit_ident) { 02106 02107 /* 02108 * Attempt slit identification: this recipe may continue even 02109 * in case of failed identification (i.e., the position table is 02110 * not produced, but an error is not set). In case of failure, 02111 * the spectra would be still extracted, even if they would not 02112 * be associated to slits on the mask. 02113 * 02114 * The reason for making the slit identification an user option 02115 * (via the parameter slit_ident) is to offer the possibility 02116 * to avoid identifications that are only apparently successful, 02117 * as it would happen in the case of an incorrect slit description 02118 * in the data header. 02119 */ 02120 02121 cpl_msg_indent_less(); 02122 cpl_msg_info(recipe, "Attempt slit identification (optional)..."); 02123 cpl_msg_indent_more(); 02124 02125 positions = mos_identify_slits(slits, maskslits, NULL); 02126 02127 if (positions) { 02128 cpl_table_delete(slits); 02129 slits = positions; 02130 02131 /* 02132 * Eliminate slits which are _entirely_ outside the CCD 02133 */ 02134 02135 cpl_table_and_selected_double(slits, 02136 "ybottom", CPL_GREATER_THAN, ny-1); 02137 cpl_table_or_selected_double(slits, 02138 "ytop", CPL_LESS_THAN, 0); 02139 cpl_table_erase_selected(slits); 02140 02141 nslits = cpl_table_get_nrow(slits); 02142 02143 if (nslits == 0) 02144 fors_calib_exit("No slits found on the CCD"); 02145 02146 cpl_msg_info(recipe, "%d slits are entirely or partially " 02147 "contained in CCD", nslits); 02148 02149 } 02150 else { 02151 slit_ident = 0; 02152 cpl_msg_info(recipe, "Global distortion model cannot be computed"); 02153 if (cpl_error_get_code() != CPL_ERROR_NONE) { 02154 fors_calib_exit(NULL); 02155 } 02156 } 02157 } 02158 02159 02160 /* 02161 * Determination of spectral curvature 02162 */ 02163 02164 cpl_msg_indent_less(); 02165 cpl_msg_info(recipe, "Determining spectral curvature..."); 02166 cpl_msg_indent_more(); 02167 02168 cpl_msg_info(recipe, "Tracing master flat field spectra edges..."); 02169 traces = mos_trace_flat(trace_flat, slits, reference, 02170 startwavelength, endwavelength, dispersion); 02171 02172 if (!traces) 02173 fors_calib_exit("Tracing failure"); 02174 02175 cpl_image_delete(added_flat); added_flat = NULL; 02176 02177 cpl_msg_info(recipe, "Fitting flat field spectra edges..."); 02178 polytraces = mos_poly_trace(slits, traces, cdegree); 02179 02180 if (!polytraces) 02181 fors_calib_exit("Trace fitting failure"); 02182 02183 if (cmode) { 02184 cpl_msg_info(recipe, "Computing global spectral curvature model..."); 02185 mos_global_trace(slits, polytraces, cmode); 02186 } 02187 02188 if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist, 02189 recipe, version)) 02190 fors_calib_exit(NULL); 02191 02192 cpl_table_delete(traces); traces = NULL; 02193 02194 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 02195 spatial = mos_spatial_calibration(spectra, slits, polytraces, reference, 02196 startwavelength, endwavelength, 02197 dispersion, 0, coordinate); 02198 02199 if (!slit_ident) { 02200 cpl_image_delete(spectra); spectra = NULL; 02201 } 02202 02203 /* 02204 * Flat field normalisation is done directly on the master flat 02205 * field (without spatial rectification first). The spectral 02206 * curvature model may be provided in input, in future releases. 02207 */ 02208 02209 cpl_msg_indent_less(); 02210 cpl_msg_info(recipe, "Perform flat field normalisation..."); 02211 cpl_msg_indent_more(); 02212 02213 norm_flat = cpl_image_duplicate(master_flat); 02214 02215 smo_flat = mos_normalise_flat(norm_flat, coordinate, slits, polytraces, 02216 reference, startwavelength, endwavelength, 02217 dispersion, dradius, ddegree); 02218 02219 cpl_image_delete(smo_flat); smo_flat = NULL; /* It may be a product */ 02220 02221 02222 save_header = dfs_load_header(frameset, flat_tag, 0); 02223 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", nflats); 02224 //%%% 02225 rect_flat = mos_spatial_calibration(master_flat, slits, polytraces, 02226 reference, startwavelength, 02227 endwavelength, dispersion, 0, NULL); 02228 rect_nflat = mos_spatial_calibration(norm_flat, slits, polytraces, 02229 reference, startwavelength, 02230 endwavelength, dispersion, 0, NULL); 02231 //%%% 02232 02233 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag, 02234 save_header, parlist, recipe, version)) 02235 fors_calib_exit(NULL); 02236 02237 cpl_image_delete(master_flat); master_flat = NULL; 02238 02239 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag, 02240 save_header, parlist, recipe, version)) 02241 fors_calib_exit(NULL); 02242 02243 cpl_image_delete(norm_flat); norm_flat = NULL; 02244 cpl_propertylist_delete(save_header); save_header = NULL; 02245 02246 02247 /* 02248 * Final wavelength calibration of spectra having their curvature 02249 * removed 02250 */ 02251 02252 cpl_msg_indent_less(); 02253 cpl_msg_info(recipe, "Perform final wavelength calibration..."); 02254 cpl_msg_indent_more(); 02255 02256 nx = cpl_image_get_size_x(spatial); 02257 ny = cpl_image_get_size_y(spatial); 02258 02259 idscoeff = cpl_table_new(ny); 02260 restable = cpl_table_new(nlines); 02261 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 02262 if (check) 02263 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 02264 fiterror = cpl_calloc(ny, sizeof(double)); 02265 fitlines = cpl_calloc(ny, sizeof(int)); 02266 02267 rectified = mos_wavelength_calibration_final(spatial, slits, lines, 02268 dispersion, peakdetection, 02269 wradius, wdegree, wreject, 02270 reference, &startwavelength, 02271 &endwavelength, fitlines, 02272 fiterror, idscoeff, rainbow, 02273 residual, restable); 02274 02275 /* 02276 dfs_save_image(frameset, rainbow, "rainbow_calib", NULL, parlist, recipe, version); 02277 */ 02278 02279 if (rectified == NULL) 02280 fors_calib_exit("Wavelength calibration failure."); 02281 02282 if (dfs_save_table(frameset, restable, disp_residuals_table_tag, NULL, 02283 parlist, recipe, version)) 02284 fors_calib_exit(NULL); 02285 02286 cpl_table_delete(restable); restable = NULL; 02287 02288 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 02289 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 02290 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 02291 02292 for (i = 0; i < ny; i++) 02293 if (!cpl_table_is_valid(idscoeff, "c0", i)) 02294 cpl_table_set_invalid(idscoeff, "error", i); 02295 02296 if (wmosmode > 0) { 02297 mos_interpolate_wavecalib_slit(idscoeff, slits, 1, wmosmode - 1); 02298 02299 cpl_image_delete(rectified); 02300 02301 rectified = mos_wavelength_calibration(spatial, reference, 02302 startwavelength, endwavelength, 02303 dispersion, idscoeff, 0); 02304 } 02305 02306 cpl_image_delete(spatial); spatial = NULL; 02307 02308 delta = mos_map_pixel(idscoeff, reference, startwavelength, 02309 endwavelength, dispersion, 2); 02310 02311 header = cpl_propertylist_new(); 02312 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 02313 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 02314 cpl_propertylist_update_double(header, "CRVAL1", 02315 startwavelength + dispersion/2); 02316 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02317 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02318 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02319 cpl_propertylist_update_double(header, "CD1_1", dispersion); 02320 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02321 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02322 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02323 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02324 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02325 02326 if (dfs_save_image(frameset, delta, delta_image_tag, 02327 header, parlist, recipe, version)) 02328 fors_calib_exit(NULL); 02329 02330 cpl_image_delete(delta); delta = NULL; 02331 cpl_propertylist_delete(header); header = NULL; 02332 02333 mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 02334 dispersion, 6, 0); 02335 02336 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms); 02337 02338 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 02339 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error"); 02340 02341 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 02342 mean_rms, mean_rms * dispersion); 02343 02344 restab = mos_resolution_table(rectified, startwavelength, dispersion, 02345 60000, lines); 02346 02347 if (restab) { 02348 cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 02349 cpl_table_get_column_mean(restab, "resolution")); 02350 cpl_msg_info(recipe, "Mean reference lines FWHM: %.2f +/- %.2f pixel", 02351 cpl_table_get_column_mean(restab, "fwhm") / dispersion, 02352 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion); 02353 02354 if (qc) { 02355 02356 qclist = cpl_propertylist_new(); 02357 02358 /* 02359 * QC1 parameters 02360 */ 02361 keyname = "QC.DID"; 02362 02363 if (fors_header_write_string(qclist, 02364 keyname, 02365 "2.0", 02366 "QC1 dictionary")) { 02367 fors_calib_exit("Cannot write dictionary version " 02368 "to QC log file"); 02369 } 02370 02371 if (mos) 02372 keyname = "QC.MOS.RESOLUTION"; 02373 else 02374 keyname = "QC.MXU.RESOLUTION"; 02375 02376 if (fors_header_write_double(qclist, 02377 cpl_table_get_column_mean(restab, 02378 "resolution"), 02379 keyname, 02380 "Angstrom", 02381 "Mean spectral resolution")) { 02382 fors_calib_exit("Cannot write mean spectral resolution to QC " 02383 "log file"); 02384 } 02385 02386 if (mos) 02387 keyname = "QC.MOS.RESOLUTION.RMS"; 02388 else 02389 keyname = "QC.MXU.RESOLUTION.RMS"; 02390 02391 if (fors_header_write_double(qclist, 02392 cpl_table_get_column_stdev(restab, 02393 "resolution"), 02394 keyname, 02395 "Angstrom", 02396 "Scatter of spectral resolution")) { 02397 fors_calib_exit("Cannot write spectral resolution scatter " 02398 "to QC log file"); 02399 } 02400 02401 if (mos) 02402 keyname = "QC.MOS.RESOLUTION.NWAVE"; 02403 else 02404 keyname = "QC.MXU.RESOLUTION.NWAVE"; 02405 02406 if (fors_header_write_int(qclist, cpl_table_get_nrow(restab) - 02407 cpl_table_count_invalid(restab, 02408 "resolution"), 02409 keyname, 02410 NULL, 02411 "Number of examined wavelengths " 02412 "for resolution computation")) { 02413 fors_calib_exit("Cannot write number of lines used in " 02414 "spectral resolution computation " 02415 "to QC log file"); 02416 } 02417 02418 if (mos) 02419 keyname = "QC.MOS.RESOLUTION.MEANRMS"; 02420 else 02421 keyname = "QC.MXU.RESOLUTION.MEANRMS"; 02422 02423 if (fors_header_write_double(qclist, 02424 cpl_table_get_column_mean(restab, 02425 "resolution_rms"), 02426 keyname, NULL, 02427 "Mean error on spectral " 02428 "resolution computation")) { 02429 fors_calib_exit("Cannot write mean error in " 02430 "spectral resolution computation " 02431 "to QC log file"); 02432 } 02433 02434 if (mos) 02435 keyname = "QC.MOS.RESOLUTION.NLINES"; 02436 else 02437 keyname = "QC.MXU.RESOLUTION.NLINES"; 02438 02439 if (fors_header_write_int(qclist, 02440 cpl_table_get_column_mean(restab, "nlines") * 02441 cpl_table_get_nrow(restab), 02442 keyname, NULL, 02443 "Number of lines for spectral " 02444 "resolution computation")) { 02445 fors_calib_exit("Cannot write number of examined " 02446 "wavelengths in spectral resolution computation " 02447 "to QC log file"); 02448 } 02449 } 02450 02451 if (dfs_save_table(frameset, restab, spectral_resolution_tag, qclist, 02452 parlist, recipe, version)) 02453 fors_calib_exit(NULL); 02454 02455 cpl_table_delete(restab); restab = NULL; 02456 cpl_propertylist_delete(qclist); qclist = NULL; 02457 02458 } 02459 else 02460 fors_calib_exit("Cannot compute the spectral resolution table"); 02461 02462 cpl_vector_delete(lines); lines = NULL; 02463 02464 if (dfs_save_table(frameset, idscoeff, disp_coeff_tag, NULL, 02465 parlist, recipe, version)) 02466 fors_calib_exit(NULL); 02467 //%%% 02468 02469 mapped_flat = mos_wavelength_calibration(rect_flat, reference, 02470 startwavelength, endwavelength, 02471 dispersion, idscoeff, 0); 02472 02473 mapped_nflat = mos_wavelength_calibration(rect_nflat, reference, 02474 startwavelength, endwavelength, 02475 dispersion, idscoeff, 0); 02476 02477 cpl_image_delete(rect_flat); rect_flat = NULL; 02478 cpl_image_delete(rect_nflat); rect_nflat = NULL; 02479 //%%% 02480 02481 /* 02482 * Global distortion models 02483 */ 02484 02485 if (slit_ident) { 02486 02487 cpl_msg_info(recipe, "Computing global distortions model"); 02488 global = mos_global_distortion(slits, maskslits, idscoeff, 02489 polytraces, reference); 02490 02491 if (global && 0) { 02492 cpl_table *stest; 02493 cpl_table *ctest; 02494 cpl_table *dtest; 02495 cpl_image *itest; 02496 02497 stest = mos_build_slit_location(global, maskslits, ccd_ysize); 02498 02499 ctest = mos_build_curv_coeff(global, maskslits, stest); 02500 if (dfs_save_table(frameset, ctest, "CURVS", NULL, 02501 parlist, recipe, version)) 02502 fors_calib_exit(NULL); 02503 02504 itest = mos_spatial_calibration(spectra, stest, ctest, 02505 reference, startwavelength, 02506 endwavelength, dispersion, 02507 0, NULL); 02508 cpl_table_delete(ctest); ctest = NULL; 02509 cpl_image_delete(itest); itest = NULL; 02510 if (dfs_save_table(frameset, stest, "SLITS", NULL, 02511 parlist, recipe, version)) 02512 fors_calib_exit(NULL); 02513 02514 dtest = mos_build_disp_coeff(global, stest); 02515 if (dfs_save_table(frameset, dtest, "DISPS", NULL, 02516 parlist, recipe, version)) 02517 fors_calib_exit(NULL); 02518 02519 cpl_table_delete(dtest); dtest = NULL; 02520 cpl_table_delete(stest); stest = NULL; 02521 } 02522 02523 if (global) { 02524 if (dfs_save_table(frameset, global, global_distortion_tag, NULL, 02525 parlist, recipe, version)) 02526 fors_calib_exit(NULL); 02527 cpl_table_delete(global); global = NULL; 02528 } 02529 02530 cpl_image_delete(spectra); spectra = NULL; 02531 cpl_table_delete(maskslits); maskslits = NULL; 02532 } 02533 02534 cpl_table_delete(idscoeff); idscoeff = NULL; 02535 02536 header = cpl_propertylist_new(); 02537 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 02538 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 02539 cpl_propertylist_update_double(header, "CRVAL1", 02540 startwavelength + dispersion/2); 02541 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02542 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02543 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02544 cpl_propertylist_update_double(header, "CD1_1", dispersion); 02545 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02546 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02547 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02548 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02549 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02550 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1); 02551 02552 if (dfs_save_image(frameset, rectified, reduced_lamp_tag, header, 02553 parlist, recipe, version)) 02554 fors_calib_exit(NULL); 02555 02556 cpl_image_delete(rectified); rectified = NULL; 02557 //%%% 02558 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", nflats); 02559 02560 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag, header, 02561 parlist, recipe, version)) 02562 fors_calib_exit(NULL); 02563 02564 cpl_image_delete(mapped_flat); mapped_flat = NULL; 02565 02566 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag, header, 02567 parlist, recipe, version)) 02568 fors_calib_exit(NULL); 02569 02570 cpl_image_delete(mapped_nflat); mapped_nflat = NULL; 02571 02572 cpl_propertylist_delete(header); header = NULL; 02573 02574 if (check) { 02575 save_header = dfs_load_header(frameset, arc_tag, 0); 02576 02577 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0); 02578 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0); 02579 /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */ 02580 cpl_propertylist_update_double(save_header, "CD1_1", 1.0); 02581 cpl_propertylist_update_double(save_header, "CD1_2", 0.0); 02582 cpl_propertylist_update_double(save_header, "CD2_1", 0.0); 02583 cpl_propertylist_update_double(save_header, "CD2_2", 1.0); 02584 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR"); 02585 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL"); 02586 02587 if (dfs_save_image(frameset, residual, disp_residuals_tag, save_header, 02588 parlist, recipe, version)) 02589 fors_calib_exit(NULL); 02590 02591 cpl_image_delete(residual); residual = NULL; 02592 cpl_propertylist_delete(save_header); save_header = NULL; 02593 } 02594 02595 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, polytraces, 02596 reference, startwavelength, endwavelength, 02597 dispersion); 02598 02599 cpl_image_delete(rainbow); rainbow = NULL; 02600 02601 save_header = dfs_load_header(frameset, arc_tag, 0); 02602 02603 if (qc) { 02604 02605 /* 02606 * QC1 parameters 02607 */ 02608 keyname = "QC.DID"; 02609 02610 if (fors_header_write_string(save_header, 02611 keyname, 02612 "2.0", 02613 "QC1 dictionary")) { 02614 fors_calib_exit("Cannot write dictionary version " 02615 "to QC log file"); 02616 } 02617 02618 if (fors_header_write_double(save_header, 02619 mean_rms, 02620 "QC.WAVE.ACCURACY", 02621 "pixel", 02622 "Mean accuracy of wavecalib model")) { 02623 fors_calib_exit("Cannot write mean wavelength calibration " 02624 "accuracy to QC log file"); 02625 } 02626 02627 02628 if (fors_header_write_double(save_header, 02629 mean_rms_err, 02630 "QC.WAVE.ACCURACY.ERROR", 02631 "pixel", 02632 "Error on accuracy of wavecalib model")) { 02633 fors_calib_exit("Cannot write error on wavelength calibration " 02634 "accuracy to QC log file"); 02635 } 02636 } 02637 02638 if (dfs_save_image(frameset, wavemap, wavelength_map_tag, save_header, 02639 parlist, recipe, version)) 02640 fors_calib_exit(NULL); 02641 02642 cpl_image_delete(wavemap); wavemap = NULL; 02643 02644 cpl_propertylist_erase_regexp(save_header, "^ESO QC ", 0); 02645 02646 if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header, 02647 parlist, recipe, version)) 02648 fors_calib_exit(NULL); 02649 02650 cpl_image_delete(coordinate); coordinate = NULL; 02651 cpl_propertylist_delete(save_header); save_header = NULL; 02652 02653 header = NULL; /* To be really, really, REALLY sure... */ 02654 02655 if (qc) { 02656 02657 double maxpos, maxneg, maxcurve, maxslope; 02658 02659 header = dfs_load_header(frameset, arc_tag, 0); 02660 02661 /* 02662 * QC1 parameters 02663 */ 02664 keyname = "QC.DID"; 02665 02666 if (fors_header_write_string(header, 02667 keyname, 02668 "2.0", 02669 "QC1 dictionary")) { 02670 fors_calib_exit("Cannot write dictionary version " 02671 "to QC log file"); 02672 } 02673 02674 maxpos = fabs(cpl_table_get_column_max(polytraces, "c2")); 02675 maxneg = fabs(cpl_table_get_column_min(polytraces, "c2")); 02676 maxcurve = maxpos > maxneg ? maxpos : maxneg; 02677 if (fors_header_write_double(header, 02678 maxcurve, 02679 "QC.TRACE.MAX.CURVATURE", 02680 "Y pixel / X pixel ^2", 02681 "Max observed curvature in " 02682 "spectral tracing")) { 02683 fors_calib_exit("Cannot write max observed curvature in spectral " 02684 "tracing to QC log file"); 02685 } 02686 02687 maxpos = fabs(cpl_table_get_column_max(polytraces, "c1")); 02688 maxneg = fabs(cpl_table_get_column_min(polytraces, "c1")); 02689 maxslope = maxpos > maxneg ? maxpos : maxneg; 02690 if (fors_header_write_double(header, 02691 maxslope, 02692 "QC.TRACE.MAX.SLOPE", 02693 "Y pixel / X pixel", 02694 "Max observed slope in spectral tracing")) { 02695 fors_calib_exit("Cannot write max observed slope in spectral " 02696 "tracing to QC log file"); 02697 } 02698 02699 // fors_qc_end_group(); 02700 } 02701 02702 cpl_free(instrume); instrume = NULL; 02703 02704 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, header, 02705 parlist, recipe, version)) 02706 fors_calib_exit(NULL); 02707 02708 cpl_propertylist_delete(header); header = NULL; 02709 cpl_table_delete(polytraces); polytraces = NULL; 02710 02711 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 02712 parlist, recipe, version)) 02713 fors_calib_exit(NULL); 02714 02715 cpl_table_delete(slits); slits = NULL; 02716 02717 if (cpl_error_get_code()) { 02718 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 02719 fors_calib_exit(NULL); 02720 } 02721 02722 return 0; 02723 } 02724