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