FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_pmos_calib.c,v 1.37 2013/02/28 15:15:10 cgarcia Exp $ 00002 * 00003 * This file is part of the FORS Data Reduction Pipeline 00004 * Copyright (C) 2002-2010 European Southern Observatory 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 /* 00022 * $Author: cgarcia $ 00023 * $Date: 2013/02/28 15:15:10 $ 00024 * $Revision: 1.37 $ 00025 * $Name: fors-4_9_20 $ 00026 */ 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <math.h> 00033 #include <string.h> 00034 #include <ctype.h> 00035 #include <cpl.h> 00036 #include <moses.h> 00037 #include <fors_stack.h> 00038 #include <fors_dfs.h> 00039 #include <fors_header.h> 00040 00041 #define OFFSET 50 00042 #define TOLERANCE 10 00043 00044 static int fors_pmos_calib_create(cpl_plugin *); 00045 static int fors_pmos_calib_exec(cpl_plugin *); 00046 static int fors_pmos_calib_destroy(cpl_plugin *); 00047 static int fors_pmos_calib(cpl_parameterlist *, cpl_frameset *); 00048 00049 static char fors_pmos_calib_description[] = 00050 "This recipe is used to identify reference lines on PMOS arc lamp\n" 00051 "exposures, and trace the spectral edges on the corresponding flat field\n" 00052 "exposures. This information is used to determine the spectral extraction\n" 00053 "mask to be applied in the scientific data reduction, performed with the\n" 00054 "recipe fors_science.\n" 00055 "This recipe accepts both FORS1 and FORS2 frames. The input arc lamps and\n" 00056 "flat field exposures are assumed to be obtained quasi-simultaneously, so\n" 00057 "that they would be described by exactly the same instrument distortions.\n" 00058 "A line catalog must be specified, containing the wavelengths of the\n" 00059 "reference arc lamp lines used for the wavelength calibration. A grism\n" 00060 "table (typically depending on the instrument mode, and in particular on\n" 00061 "the grism used) may also be specified: this table contains a default\n" 00062 "recipe parameter setting to control the way spectra are extracted for\n" 00063 "a specific instrument mode, as it is used for automatic run of the\n" 00064 "pipeline on Paranal and in Garching. If this table is specified, it\n" 00065 "will modify the default recipe parameter setting, with the exception of\n" 00066 "those parameters which have been explicitly modifyed on the command line.\n" 00067 "If a grism table is not specified, the input recipe parameters values\n" 00068 "will always be read from the command line, or from an esorex configuration\n" 00069 "file if present, or from their generic default values (that are rarely\n" 00070 "meaningful). Finally a master bias frame must be input to this recipe.\n" 00071 "The products SPECTRA_DETECTION_PMOS, SLIT_MAP_PMOS, and DISP_RESIDUALS_PMOS,\n" 00072 "are just created if the --check parameter is set to true.\n" 00073 "The MASTER_DISTORTION_TABLE is marked as required, but it is not so if all\n" 00074 "slits have different offsets, and in the case of FORS1 observations made\n" 00075 "with the old TK2048EB4-1 1604 chip read in windowed mode (2048x400)\n\n" 00076 "Input files:\n\n" 00077 " DO category: Type: Explanation: Required:\n" 00078 " SCREEN_FLAT_PMOS Raw Flat field exposures Y\n" 00079 " LAMP_PMOS Raw Arc lamp exposure Y\n" 00080 " MASTER_BIAS or BIAS Calib Bias frame Y\n" 00081 " MASTER_LINECAT Calib Line catalog Y\n" 00082 " GRISM_TABLE Calib Grism table .\n" 00083 " MASTER_DISTORTION_TABLE Calib Master distortions table Y\n\n" 00084 "Output files:\n\n" 00085 " DO category: Data type: Explanation:\n" 00086 " MASTER_SCREEN_FLAT_PMOS FITS image Combined (sum) flat field\n" 00087 " MASTER_NORM_FLAT_PMOS FITS image Normalised flat field\n" 00088 " MAPPED_SCREEN_FLAT_PMOS FITS image Wavelength calibrated flat field\n" 00089 " MAPPED_NORM_FLAT_PMOS FITS image Wavelength calibrated normalised flat\n" 00090 " REDUCED_LAMP_PMOS FITS image Wavelength calibrated arc spectrum\n" 00091 " DISP_COEFF_PMOS FITS table Inverse dispersion coefficients\n" 00092 " DISP_RESIDUALS_PMOS FITS image Residuals in wavelength calibration\n" 00093 " DISP_RESIDUALS_TABLE_PMOS FITS table Residuals in wavelength calibration\n" 00094 " DELTA_IMAGE_PMOS FITS image Offset vs linear wavelength calib\n" 00095 " WAVELENGTH_MAP_PMOS FITS image Wavelength for each pixel on CCD\n" 00096 " SPECTRA_DETECTION_PMOS FITS image Check for preliminary detection\n" 00097 " SLIT_MAP_PMOS FITS image Map of central wavelength on CCD\n" 00098 " CURV_TRACES_PMOS FITS table Spectral curvature traces\n" 00099 " CURV_COEFF_PMOS FITS table Spectral curvature coefficients\n" 00100 " SPATIAL_MAP_PMOS FITS image Spatial position along slit on CCD\n" 00101 " SPECTRAL_RESOLUTION_PMOS FITS table Resolution at reference arc lines\n" 00102 " SLIT_LOCATION_PMOS FITS table Slits on product frames and CCD\n\n"; 00103 00104 #define fors_pmos_calib_exit(message) \ 00105 { \ 00106 if (message) cpl_msg_error(recipe, message); \ 00107 cpl_free(instrume); \ 00108 cpl_free(fiterror); \ 00109 cpl_free(fitlines); \ 00110 cpl_image_delete(bias); \ 00111 cpl_image_delete(master_bias); \ 00112 cpl_image_delete(coordinate); \ 00113 cpl_image_delete(checkwave); \ 00114 cpl_image_delete(flat); \ 00115 cpl_image_delete(master_flat); \ 00116 cpl_image_delete(added_flat); \ 00117 cpl_image_delete(norm_flat); \ 00118 cpl_image_delete(mapped_flat); \ 00119 cpl_image_delete(mapped_nflat); \ 00120 cpl_image_delete(rainbow); \ 00121 cpl_image_delete(rectified); \ 00122 cpl_image_delete(residual); \ 00123 cpl_image_delete(smo_flat); \ 00124 cpl_image_delete(spatial); \ 00125 cpl_image_delete(spectra); \ 00126 cpl_image_delete(wavemap); \ 00127 cpl_image_delete(delta); \ 00128 cpl_image_delete(rect_flat); \ 00129 cpl_image_delete(rect_nflat); \ 00130 cpl_image_delete(mapped_flat); \ 00131 cpl_image_delete(mapped_nflat); \ 00132 cpl_mask_delete(refmask); \ 00133 cpl_propertylist_delete(header); \ 00134 cpl_propertylist_delete(save_header); \ 00135 cpl_propertylist_delete(qclist); \ 00136 cpl_table_delete(grism_table); \ 00137 cpl_table_delete(idscoeff); \ 00138 cpl_table_delete(idscoeff_all); \ 00139 cpl_table_delete(restable); \ 00140 cpl_table_delete(maskslits); \ 00141 cpl_table_delete(overscans); \ 00142 cpl_table_delete(traces); \ 00143 cpl_table_delete(polytraces); \ 00144 cpl_table_delete(slits); \ 00145 cpl_table_delete(restab); \ 00146 cpl_table_delete(global); \ 00147 cpl_table_delete(wavelengths); \ 00148 cpl_vector_delete(lines); \ 00149 cpl_msg_indent_less(); \ 00150 return -1; \ 00151 } 00152 00153 #define fors_pmos_calib_exit_memcheck(message) \ 00154 { \ 00155 if (message) cpl_msg_info(recipe, message); \ 00156 printf("free instrume (%p)\n", instrume); \ 00157 cpl_free(instrume); \ 00158 printf("free pipefile (%p)\n", pipefile); \ 00159 cpl_free(pipefile); \ 00160 printf("free fiterror (%p)\n", fiterror); \ 00161 cpl_free(fiterror); \ 00162 printf("free fitlines (%p)\n", fitlines); \ 00163 cpl_free(fitlines); \ 00164 printf("free bias (%p)\n", bias); \ 00165 cpl_image_delete(bias); \ 00166 printf("free master_bias (%p)\n", master_bias); \ 00167 cpl_image_delete(master_bias); \ 00168 printf("free coordinate (%p)\n", coordinate); \ 00169 cpl_image_delete(coordinate); \ 00170 printf("free checkwave (%p)\n", checkwave); \ 00171 cpl_image_delete(checkwave); \ 00172 printf("free flat (%p)\n", flat); \ 00173 cpl_image_delete(flat); \ 00174 printf("free master_flat (%p)\n", master_flat); \ 00175 cpl_image_delete(master_flat); \ 00176 printf("free norm_flat (%p)\n", norm_flat); \ 00177 cpl_image_delete(norm_flat); \ 00178 printf("free mapped_flat (%p)\n", mapped_flat); \ 00179 cpl_image_delete(mapped_flat); \ 00180 printf("free mapped_nflat (%p)\n", mapped_nflat); \ 00181 cpl_image_delete(mapped_nflat); \ 00182 printf("free rainbow (%p)\n", rainbow); \ 00183 cpl_image_delete(rainbow); \ 00184 printf("free rectified (%p)\n", rectified); \ 00185 cpl_image_delete(rectified); \ 00186 printf("free residual (%p)\n", residual); \ 00187 cpl_image_delete(residual); \ 00188 printf("free smo_flat (%p)\n", smo_flat); \ 00189 cpl_image_delete(smo_flat); \ 00190 printf("free spatial (%p)\n", spatial); \ 00191 cpl_image_delete(spatial); \ 00192 printf("free spectra (%p)\n", spectra); \ 00193 cpl_image_delete(spectra); \ 00194 printf("free wavemap (%p)\n", wavemap); \ 00195 cpl_image_delete(wavemap); \ 00196 printf("free delta (%p)\n", delta); \ 00197 cpl_image_delete(delta); \ 00198 printf("free rect_flat (%p)\n", rect_flat); \ 00199 cpl_image_delete(rect_flat); \ 00200 printf("free rect_nflat (%p)\n", rect_nflat); \ 00201 cpl_image_delete(rect_nflat); \ 00202 printf("free refmask (%p)\n", refmask); \ 00203 cpl_mask_delete(refmask); \ 00204 printf("free header (%p)\n", header); \ 00205 cpl_propertylist_delete(header); \ 00206 printf("free save_header (%p)\n", save_header); \ 00207 cpl_propertylist_delete(save_header); \ 00208 printf("free qclist (%p)\n", qclist); \ 00209 cpl_propertylist_delete(qclist); \ 00210 printf("free grism_table (%p)\n", grism_table); \ 00211 cpl_table_delete(grism_table); \ 00212 printf("free idscoeff (%p)\n", idscoeff); \ 00213 cpl_table_delete(idscoeff); \ 00214 printf("free idscoeff_all (%p)\n", idscoeff_all); \ 00215 cpl_table_delete(idscoeff_all); \ 00216 printf("free restable (%p)\n", restable); \ 00217 cpl_table_delete(restable); \ 00218 printf("free maskslits (%p)\n", maskslits); \ 00219 cpl_table_delete(maskslits); \ 00220 printf("free overscans (%p)\n", overscans); \ 00221 cpl_table_delete(overscans); \ 00222 printf("free traces (%p)\n", traces); \ 00223 cpl_table_delete(traces); \ 00224 printf("free polytraces (%p)\n", polytraces); \ 00225 cpl_table_delete(polytraces); \ 00226 printf("free slits (%p)\n", slits); \ 00227 cpl_table_delete(slits); \ 00228 printf("free restab (%p)\n", restab); \ 00229 cpl_table_delete(restab); \ 00230 printf("free global (%p)\n", global); \ 00231 cpl_table_delete(global); \ 00232 printf("free wavelengths (%p)\n", wavelengths); \ 00233 cpl_table_delete(wavelengths); \ 00234 printf("free lines (%p)\n", lines); \ 00235 cpl_vector_delete(lines); \ 00236 cpl_msg_indent_less(); \ 00237 return 0; \ 00238 } 00239 00240 00252 int cpl_plugin_get_info(cpl_pluginlist *list) 00253 { 00254 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00255 cpl_plugin *plugin = &recipe->interface; 00256 00257 cpl_plugin_init(plugin, 00258 CPL_PLUGIN_API, 00259 FORS_BINARY_VERSION, 00260 CPL_PLUGIN_TYPE_RECIPE, 00261 "fors_pmos_calib", 00262 "Determination of the extraction mask", 00263 fors_pmos_calib_description, 00264 "Carlo Izzo", 00265 PACKAGE_BUGREPORT, 00266 "This file is currently part of the FORS Instrument Pipeline\n" 00267 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00268 "This program is free software; you can redistribute it and/or modify\n" 00269 "it under the terms of the GNU General Public License as published by\n" 00270 "the Free Software Foundation; either version 2 of the License, or\n" 00271 "(at your option) any later version.\n\n" 00272 "This program is distributed in the hope that it will be useful,\n" 00273 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00274 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00275 "GNU General Public License for more details.\n\n" 00276 "You should have received a copy of the GNU General Public License\n" 00277 "along with this program; if not, write to the Free Software Foundation,\n" 00278 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00279 fors_pmos_calib_create, 00280 fors_pmos_calib_exec, 00281 fors_pmos_calib_destroy); 00282 00283 cpl_pluginlist_append(list, plugin); 00284 00285 return 0; 00286 } 00287 00288 00299 static int fors_pmos_calib_create(cpl_plugin *plugin) 00300 { 00301 cpl_recipe *recipe; 00302 cpl_parameter *p; 00303 00304 00305 /* 00306 * Check that the plugin is part of a valid recipe 00307 */ 00308 00309 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00310 recipe = (cpl_recipe *)plugin; 00311 else 00312 return -1; 00313 00314 /* 00315 * Create the parameters list in the cpl_recipe object 00316 */ 00317 00318 recipe->parameters = cpl_parameterlist_new(); 00319 00320 00321 /* 00322 * Dispersion 00323 */ 00324 00325 p = cpl_parameter_new_value("fors.fors_pmos_calib.dispersion", 00326 CPL_TYPE_DOUBLE, 00327 "Expected spectral dispersion (Angstrom/pixel)", 00328 "fors.fors_pmos_calib", 00329 0.0); 00330 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00331 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00332 cpl_parameterlist_append(recipe->parameters, p); 00333 00334 /* 00335 * Peak detection level 00336 */ 00337 00338 p = cpl_parameter_new_value("fors.fors_pmos_calib.peakdetection", 00339 CPL_TYPE_DOUBLE, 00340 "Initial peak detection threshold (ADU)", 00341 "fors.fors_pmos_calib", 00342 0.0); 00343 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "peakdetection"); 00344 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00345 cpl_parameterlist_append(recipe->parameters, p); 00346 00347 /* 00348 * Degree of wavelength calibration polynomial 00349 */ 00350 00351 p = cpl_parameter_new_value("fors.fors_pmos_calib.wdegree", 00352 CPL_TYPE_INT, 00353 "Degree of wavelength calibration polynomial", 00354 "fors.fors_pmos_calib", 00355 0); 00356 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wdegree"); 00357 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00358 cpl_parameterlist_append(recipe->parameters, p); 00359 00360 /* 00361 * Reference lines search radius 00362 */ 00363 00364 p = cpl_parameter_new_value("fors.fors_pmos_calib.wradius", 00365 CPL_TYPE_INT, 00366 "Search radius if iterating pattern-matching " 00367 "with first-guess method", 00368 "fors.fors_pmos_calib", 00369 4); 00370 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wradius"); 00371 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00372 cpl_parameterlist_append(recipe->parameters, p); 00373 00374 /* 00375 * Rejection threshold in dispersion relation polynomial fitting 00376 */ 00377 00378 p = cpl_parameter_new_value("fors.fors_pmos_calib.wreject", 00379 CPL_TYPE_DOUBLE, 00380 "Rejection threshold in dispersion " 00381 "relation fit (pixel)", 00382 "fors.fors_pmos_calib", 00383 0.7); 00384 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wreject"); 00385 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00386 cpl_parameterlist_append(recipe->parameters, p); 00387 00388 /* 00389 * Line catalog table column containing the reference wavelengths 00390 */ 00391 00392 p = cpl_parameter_new_value("fors.fors_pmos_calib.wcolumn", 00393 CPL_TYPE_STRING, 00394 "Name of line catalog table column " 00395 "with wavelengths", 00396 "fors.fors_pmos_calib", 00397 "WLEN"); 00398 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn"); 00399 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00400 cpl_parameterlist_append(recipe->parameters, p); 00401 00402 /* 00403 * Degree of spectral curvature polynomial 00404 */ 00405 00406 p = cpl_parameter_new_value("fors.fors_pmos_calib.cdegree", 00407 CPL_TYPE_INT, 00408 "Degree of spectral curvature polynomial", 00409 "fors.fors_pmos_calib", 00410 0); 00411 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree"); 00412 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00413 cpl_parameterlist_append(recipe->parameters, p); 00414 00415 /* 00416 * Curvature solution interpolation 00417 */ 00418 00419 p = cpl_parameter_new_value("fors.fors_pmos_calib.cmode", 00420 CPL_TYPE_INT, 00421 "Interpolation mode of curvature solution " 00422 "(0 = no " 00423 "interpolation, 1 = fill gaps, 2 = global " 00424 "model)", 00425 "fors.fors_pmos_calib", 00426 1); 00427 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode"); 00428 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00429 cpl_parameterlist_append(recipe->parameters, p); 00430 00431 /* 00432 * Start wavelength for spectral extraction 00433 */ 00434 00435 p = cpl_parameter_new_value("fors.fors_pmos_calib.startwavelength", 00436 CPL_TYPE_DOUBLE, 00437 "Start wavelength in spectral extraction", 00438 "fors.fors_pmos_calib", 00439 0.0); 00440 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00441 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00442 cpl_parameterlist_append(recipe->parameters, p); 00443 00444 /* 00445 * End wavelength for spectral extraction 00446 */ 00447 00448 p = cpl_parameter_new_value("fors.fors_pmos_calib.endwavelength", 00449 CPL_TYPE_DOUBLE, 00450 "End wavelength in spectral extraction", 00451 "fors.fors_pmos_calib", 00452 0.0); 00453 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00454 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00455 cpl_parameterlist_append(recipe->parameters, p); 00456 00457 /* 00458 * Flat field frames stack parameters 00459 */ 00460 00461 fors_stack_define_parameters(recipe->parameters, "fors.fors_pmos_calib", 00462 "average"); 00463 00464 /* 00465 * Degree of flat field fitting polynomial along dispersion direction 00466 */ 00467 00468 p = cpl_parameter_new_value("fors.fors_pmos_calib.ddegree", 00469 CPL_TYPE_INT, 00470 "Degree of flat field fitting polynomial " 00471 "along dispersion direction", 00472 "fors.fors_pmos_calib", 00473 -1); 00474 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree"); 00475 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00476 cpl_parameterlist_append(recipe->parameters, p); 00477 00478 /* 00479 * Smooth box radius for flat field along dispersion direction 00480 */ 00481 00482 p = cpl_parameter_new_value("fors.fors_pmos_calib.dradius", 00483 CPL_TYPE_INT, 00484 "Smooth box radius for flat field along " 00485 "dispersion direction", 00486 "fors.fors_pmos_calib", 00487 10); 00488 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius"); 00489 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00490 cpl_parameterlist_append(recipe->parameters, p); 00491 00492 /* 00493 * Computation of QC1 parameters 00494 */ 00495 00496 p = cpl_parameter_new_value("fors.fors_pmos_calib.qc", 00497 CPL_TYPE_BOOL, 00498 "Compute QC1 parameters", 00499 "fors.fors_pmos_calib", 00500 TRUE); 00501 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc"); 00502 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00503 cpl_parameterlist_append(recipe->parameters, p); 00504 00505 /* 00506 * Create check products 00507 */ 00508 00509 p = cpl_parameter_new_value("fors.fors_pmos_calib.check", 00510 CPL_TYPE_BOOL, 00511 "Create intermediate products", 00512 "fors.fors_pmos_calib", 00513 FALSE); 00514 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check"); 00515 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00516 cpl_parameterlist_append(recipe->parameters, p); 00517 00518 return 0; 00519 } 00520 00521 00530 static int fors_pmos_calib_exec(cpl_plugin *plugin) 00531 { 00532 cpl_recipe *recipe; 00533 00534 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00535 recipe = (cpl_recipe *)plugin; 00536 else 00537 return -1; 00538 00539 return fors_pmos_calib(recipe->parameters, recipe->frames); 00540 } 00541 00542 00551 static int fors_pmos_calib_destroy(cpl_plugin *plugin) 00552 { 00553 cpl_recipe *recipe; 00554 00555 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00556 recipe = (cpl_recipe *)plugin; 00557 else 00558 return -1; 00559 00560 cpl_parameterlist_delete(recipe->parameters); 00561 00562 return 0; 00563 } 00564 00565 00575 static int fors_pmos_calib(cpl_parameterlist *parlist, cpl_frameset *frameset) 00576 { 00577 00578 const char *recipe = "fors_pmos_calib"; 00579 00580 00581 /* 00582 * Input parameters 00583 */ 00584 00585 double dispersion; 00586 double peakdetection; 00587 int wdegree; 00588 int wradius; 00589 double wreject; 00590 const char *wcolumn; 00591 int cdegree; 00592 int cmode; 00593 double startwavelength; 00594 double endwavelength; 00595 int ddegree; 00596 int dradius; 00597 int qc; 00598 int check; 00599 const char *stack_method; 00600 int min_reject; 00601 int max_reject; 00602 double klow; 00603 double khigh; 00604 int kiter; 00605 00606 00607 /* 00608 * CPL objects 00609 */ 00610 00611 cpl_imagelist *biases = NULL; 00612 cpl_image *bias = NULL; 00613 cpl_image *master_bias = NULL; 00614 cpl_image *multi_bias = NULL; 00615 cpl_image *flat = NULL; 00616 cpl_image *master_flat = NULL; 00617 cpl_image *added_flat = NULL; 00618 cpl_image *trace_flat = NULL; 00619 cpl_image *smo_flat = NULL; 00620 cpl_image *norm_flat = NULL; 00621 cpl_image *spectra = NULL; 00622 cpl_image *wavemap = NULL; 00623 cpl_image *delta = NULL; 00624 cpl_image *residual = NULL; 00625 cpl_image *checkwave = NULL; 00626 cpl_image *rectified = NULL; 00627 cpl_image *dummy = NULL; 00628 cpl_image *add_dummy = NULL; 00629 cpl_image *refimage = NULL; 00630 cpl_image *coordinate = NULL; 00631 cpl_image *rainbow = NULL; 00632 cpl_image *spatial = NULL; 00633 cpl_image *rect_flat = NULL; 00634 cpl_image *rect_nflat = NULL; 00635 cpl_image *mapped_flat = NULL; 00636 cpl_image *mapped_nflat = NULL; 00637 00638 cpl_mask *refmask = NULL; 00639 00640 cpl_table *grism_table = NULL; 00641 cpl_table *overscans = NULL; 00642 cpl_table *wavelengths = NULL; 00643 cpl_table *idscoeff = NULL; 00644 cpl_table *idscoeff_all = NULL; 00645 cpl_table *restable = NULL; 00646 cpl_table *slits = NULL; 00647 cpl_table *positions = NULL; 00648 cpl_table *maskslits = NULL; 00649 cpl_table *traces = NULL; 00650 cpl_table *polytraces = NULL; 00651 cpl_table *restab = NULL; 00652 cpl_table *global = NULL; 00653 00654 cpl_vector *lines = NULL; 00655 00656 cpl_propertylist *header_dist = NULL; 00657 cpl_propertylist *header = NULL; 00658 cpl_propertylist *save_header = NULL; 00659 cpl_propertylist *qclist = NULL; 00660 00661 /* 00662 * Auxiliary variables 00663 */ 00664 00665 char version[80]; 00666 const char *arc_tag; 00667 const char *flat_tag; 00668 const char *master_screen_flat_tag; 00669 const char *master_norm_flat_tag; 00670 const char *reduced_lamp_tag; 00671 const char *disp_residuals_tag; 00672 const char *disp_coeff_tag; 00673 const char *wavelength_map_tag; 00674 const char *spectra_detection_tag; 00675 const char *spectral_resolution_tag; 00676 const char *slit_map_tag; 00677 const char *curv_traces_tag; 00678 const char *curv_coeff_tag; 00679 const char *spatial_map_tag; 00680 const char *slit_location_tag; 00681 const char *master_distortion_tag = "MASTER_DISTORTION_TABLE"; 00682 const char *disp_residuals_table_tag; 00683 const char *delta_image_tag; 00684 const char *mapped_screen_flat_tag; 00685 const char *mapped_norm_flat_tag; 00686 const char *keyname; 00687 int pmos; 00688 int same_offset = 0; 00689 int nslits; 00690 float *data; 00691 double *xpos; 00692 double mxpos; 00693 double mean_rms; 00694 double mean_rms_err; 00695 double alltime; 00696 int nflats; 00697 int nbias; 00698 int nlines; 00699 int rebin, rebin_dist; 00700 double *line; 00701 double *fiterror = NULL; 00702 int *fitlines = NULL; 00703 int nx, ny; 00704 double reference; 00705 double gain; 00706 int ccd_xsize, ccd_ysize; 00707 int i, j; 00708 00709 char *instrume = NULL; 00710 00711 /* 00712 * Variables just related to bagoo 00713 */ 00714 00715 int bagoo = 0; 00716 int doit = 0; 00717 double blevel = 0.0; 00718 double ron = 0.0; 00719 00720 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00721 00722 cpl_msg_set_indentation(2); 00723 00724 if (dfs_files_dont_exist(frameset)) 00725 fors_pmos_calib_exit(NULL); 00726 00727 fors_dfs_set_groups(frameset); 00728 00729 /* 00730 * Get configuration parameters 00731 */ 00732 00733 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00734 cpl_msg_indent_more(); 00735 00736 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00737 fors_pmos_calib_exit("Too many in input: GRISM_TABLE"); 00738 00739 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00740 00741 dispersion = dfs_get_parameter_double(parlist, 00742 "fors.fors_pmos_calib.dispersion", grism_table); 00743 00744 if (dispersion <= 0.0) 00745 fors_pmos_calib_exit("Invalid spectral dispersion value"); 00746 00747 peakdetection = dfs_get_parameter_double(parlist, 00748 "fors.fors_pmos_calib.peakdetection", grism_table); 00749 if (peakdetection <= 0.0) 00750 fors_pmos_calib_exit("Invalid peak detection level"); 00751 00752 wdegree = dfs_get_parameter_int(parlist, 00753 "fors.fors_pmos_calib.wdegree", grism_table); 00754 00755 if (wdegree < 1) 00756 fors_pmos_calib_exit("Invalid polynomial degree"); 00757 00758 if (wdegree > 5) 00759 fors_pmos_calib_exit("Max allowed polynomial degree is 5"); 00760 00761 wradius = dfs_get_parameter_int(parlist, 00762 "fors.fors_pmos_calib.wradius", NULL); 00763 00764 if (wradius < 0) 00765 fors_pmos_calib_exit("Invalid search radius"); 00766 00767 wreject = dfs_get_parameter_double(parlist, 00768 "fors.fors_pmos_calib.wreject", NULL); 00769 00770 if (wreject <= 0.0) 00771 fors_pmos_calib_exit("Invalid rejection threshold"); 00772 00773 wcolumn = dfs_get_parameter_string(parlist, 00774 "fors.fors_pmos_calib.wcolumn", NULL); 00775 00776 cdegree = dfs_get_parameter_int(parlist, 00777 "fors.fors_pmos_calib.cdegree", grism_table); 00778 00779 if (cdegree < 1) 00780 fors_pmos_calib_exit("Invalid polynomial degree"); 00781 00782 if (cdegree > 5) 00783 fors_pmos_calib_exit("Max allowed polynomial degree is 5"); 00784 00785 cmode = dfs_get_parameter_int(parlist, "fors.fors_pmos_calib.cmode", NULL); 00786 00787 if (cmode < 0 || cmode > 2) 00788 fors_pmos_calib_exit("Invalid curvature solution interpolation mode"); 00789 00790 startwavelength = dfs_get_parameter_double(parlist, 00791 "fors.fors_pmos_calib.startwavelength", grism_table); 00792 if (startwavelength > 1.0) 00793 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00794 fors_pmos_calib_exit("Invalid wavelength"); 00795 00796 endwavelength = dfs_get_parameter_double(parlist, 00797 "fors.fors_pmos_calib.endwavelength", grism_table); 00798 if (endwavelength > 1.0) { 00799 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00800 fors_pmos_calib_exit("Invalid wavelength"); 00801 if (startwavelength < 1.0) 00802 fors_pmos_calib_exit("Invalid wavelength interval"); 00803 } 00804 00805 if (startwavelength > 1.0) 00806 if (endwavelength - startwavelength <= 0.0) 00807 fors_pmos_calib_exit("Invalid wavelength interval"); 00808 00809 stack_method = dfs_get_parameter_string(parlist, 00810 "fors.fors_pmos_calib.stack_method", 00811 NULL); 00812 00813 if (strcmp(stack_method, "minmax") == 0) { 00814 min_reject = dfs_get_parameter_int(parlist, 00815 "fors.fors_pmos_calib.minrejection", NULL); 00816 if (min_reject < 0) 00817 fors_pmos_calib_exit("Invalid number of lower rejections"); 00818 00819 max_reject = dfs_get_parameter_int(parlist, 00820 "fors.fors_pmos_calib.maxrejection", NULL); 00821 if (max_reject < 0) 00822 fors_pmos_calib_exit("Invalid number of upper rejections"); 00823 } 00824 00825 if (strcmp(stack_method, "ksigma") == 0) { 00826 klow = dfs_get_parameter_double(parlist, 00827 "fors.fors_pmos_calib.klow", NULL); 00828 if (klow < 0.1) 00829 fors_pmos_calib_exit("Invalid lower K-sigma"); 00830 00831 khigh = dfs_get_parameter_double(parlist, 00832 "fors.fors_pmos_calib.khigh", NULL); 00833 if (khigh < 0.1) 00834 fors_pmos_calib_exit("Invalid lower K-sigma"); 00835 00836 kiter = dfs_get_parameter_int(parlist, 00837 "fors.fors_pmos_calib.kiter", NULL); 00838 if (kiter < 1) 00839 fors_pmos_calib_exit("Invalid number of iterations"); 00840 } 00841 00842 ddegree = dfs_get_parameter_int(parlist, 00843 "fors.fors_pmos_calib.ddegree", NULL); 00844 dradius = dfs_get_parameter_int(parlist, 00845 "fors.fors_pmos_calib.dradius", NULL); 00846 00847 if (dradius < 1) 00848 fors_pmos_calib_exit("Invalid smoothing box radius"); 00849 00850 qc = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.qc", NULL); 00851 00852 check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_calib.check", NULL); 00853 00854 cpl_table_delete(grism_table); grism_table = NULL; 00855 00856 if (cpl_error_get_code()) 00857 fors_pmos_calib_exit("Failure getting the configuration parameters"); 00858 00859 00860 /* 00861 * Check input set-of-frames 00862 */ 00863 00864 cpl_msg_indent_less(); 00865 cpl_msg_info(recipe, "Check input set-of-frames:"); 00866 cpl_msg_indent_more(); 00867 00868 { 00869 cpl_frameset *subframeset = cpl_frameset_duplicate(frameset); 00870 cpl_frameset_erase(subframeset, "BIAS"); 00871 cpl_frameset_erase(subframeset, "MASTER_BIAS"); 00872 00873 if (!dfs_equal_keyword(subframeset, "ESO INS GRIS1 ID")) 00874 fors_pmos_calib_exit("Input frames are not from the same grism"); 00875 00876 if (!dfs_equal_keyword(subframeset, "ESO INS FILT1 ID")) 00877 fors_pmos_calib_exit("Input frames are not from the same filter"); 00878 00879 if (!dfs_equal_keyword(subframeset, "ESO DET CHIP1 ID")) 00880 fors_pmos_calib_exit("Input frames are not from the same chip"); 00881 00882 cpl_frameset_delete(subframeset); 00883 } 00884 00885 pmos = cpl_frameset_count_tags(frameset, "LAMP_PMOS"); 00886 00887 if (pmos == 0) 00888 fors_pmos_calib_exit("Missing input arc lamp frame"); 00889 00890 if (pmos) { 00891 cpl_msg_info(recipe, "PMOS data found"); 00892 arc_tag = "LAMP_PMOS"; 00893 flat_tag = "SCREEN_FLAT_PMOS"; 00894 master_screen_flat_tag = "MASTER_SCREEN_FLAT_PMOS"; 00895 master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS"; 00896 reduced_lamp_tag = "REDUCED_LAMP_PMOS"; 00897 disp_residuals_tag = "DISP_RESIDUALS_PMOS"; 00898 disp_coeff_tag = "DISP_COEFF_PMOS"; 00899 wavelength_map_tag = "WAVELENGTH_MAP_PMOS"; 00900 spectra_detection_tag = "SPECTRA_DETECTION_PMOS"; 00901 spectral_resolution_tag = "SPECTRAL_RESOLUTION_PMOS"; 00902 slit_map_tag = "SLIT_MAP_PMOS"; 00903 curv_traces_tag = "CURV_TRACES_PMOS"; 00904 curv_coeff_tag = "CURV_COEFF_PMOS"; 00905 spatial_map_tag = "SPATIAL_MAP_PMOS"; 00906 slit_location_tag = "SLIT_LOCATION_PMOS"; 00907 disp_residuals_table_tag = "DISP_RESIDUALS_TABLE_PMOS"; 00908 delta_image_tag = "DELTA_IMAGE_PMOS"; 00909 mapped_screen_flat_tag = "MAPPED_SCREEN_FLAT_PMOS"; 00910 mapped_norm_flat_tag = "MAPPED_NORM_FLAT_PMOS"; 00911 } 00912 00913 nbias = 0; 00914 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) { 00915 if (cpl_frameset_count_tags(frameset, "BIAS") == 0) 00916 fors_pmos_calib_exit("Missing required input: MASTER_BIAS or BIAS"); 00917 nbias = cpl_frameset_count_tags(frameset, "BIAS"); 00918 } 00919 00920 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 00921 fors_pmos_calib_exit("Too many in input: MASTER_BIAS"); 00922 00923 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0) 00924 fors_pmos_calib_exit("Missing required input: MASTER_LINECAT"); 00925 00926 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1) 00927 fors_pmos_calib_exit("Too many in input: MASTER_LINECAT"); 00928 00929 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") == 0) 00930 fors_pmos_calib_exit("Missing required input: MASTER_LINECAT"); 00931 00932 if (cpl_frameset_count_tags(frameset, "MASTER_LINECAT") > 1) 00933 fors_pmos_calib_exit("Too many in input: MASTER_LINECAT"); 00934 00935 /* 00936 if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0) 00937 fors_pmos_calib_exit("Missing required input: MASTER_DISTORTION_TABLE"); 00938 */ 00939 00940 if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1) 00941 fors_pmos_calib_exit("Too many in input: MASTER_DISTORTION_TABLE"); 00942 00943 nflats = cpl_frameset_count_tags(frameset, flat_tag); 00944 00945 if (nflats < 1) { 00946 cpl_msg_error(recipe, "Missing required input: %s", flat_tag); 00947 fors_pmos_calib_exit(NULL); 00948 } 00949 00950 cpl_msg_indent_less(); 00951 00952 if (nflats > 1) 00953 cpl_msg_info(recipe, "Load %d flat field frames and stack them " 00954 "with method \"%s\"", nflats, stack_method); 00955 else 00956 cpl_msg_info(recipe, "Load flat field exposure..."); 00957 00958 cpl_msg_indent_more(); 00959 00960 header = dfs_load_header(frameset, flat_tag, 0); 00961 00962 if (header == NULL) 00963 fors_pmos_calib_exit("Cannot load flat field frame header"); 00964 00965 alltime = cpl_propertylist_get_double(header, "EXPTIME"); 00966 00967 if (cpl_error_get_code() != CPL_ERROR_NONE) 00968 fors_pmos_calib_exit("Missing keyword EXPTIME in flat field " 00969 "frame header"); 00970 00971 cpl_propertylist_delete(header); 00972 00973 for (i = 1; i < nflats; i++) { 00974 00975 header = dfs_load_header(frameset, NULL, 0); 00976 00977 if (header == NULL) 00978 fors_pmos_calib_exit("Cannot load flat field frame header"); 00979 00980 alltime += cpl_propertylist_get_double(header, "EXPTIME"); 00981 00982 if (cpl_error_get_code() != CPL_ERROR_NONE) 00983 fors_pmos_calib_exit("Missing keyword EXPTIME in flat field " 00984 "frame header"); 00985 00986 cpl_propertylist_delete(header); 00987 00988 } 00989 00990 if (bagoo) { 00991 char *montecarlo = getenv("MONTECARLO"); 00992 00993 if (montecarlo) 00994 doit = atoi(montecarlo); 00995 00996 if (doit) { 00997 master_bias = dfs_load_image(frameset, "MASTER_BIAS", 00998 CPL_TYPE_FLOAT, 0, 1); 00999 if (master_bias == NULL) 01000 fors_pmos_calib_exit("Cannot load master bias"); 01001 01002 blevel = cpl_image_get_mean(master_bias); 01003 01004 cpl_image_delete(master_bias); 01005 } 01006 } 01007 01008 master_flat = dfs_load_image(frameset, flat_tag, CPL_TYPE_FLOAT, 0, 0); 01009 01010 if (master_flat == NULL) 01011 fors_pmos_calib_exit("Cannot load flat field"); 01012 01013 if (doit) { 01014 header = dfs_load_header(frameset, flat_tag, 0); 01015 01016 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01017 01018 if (cpl_error_get_code() != CPL_ERROR_NONE) 01019 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD " 01020 "in flat field frame header"); 01021 01022 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON"); 01023 01024 if (cpl_error_get_code() != CPL_ERROR_NONE) 01025 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 RON " 01026 "in flat field frame header"); 01027 01028 cpl_propertylist_delete(header); 01029 01030 ron /= gain; // RON converted from electrons to ADU 01031 01032 mos_randomise_image(master_flat, ron, gain, blevel); 01033 } 01034 01035 ny = cpl_image_get_size_y(master_flat); 01036 01037 if (nflats > 1) { 01038 if (strcmp(stack_method, "average") == 0) { 01039 for (i = 1; i < nflats; i++) { 01040 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01041 if (flat) { 01042 if (doit) { 01043 mos_randomise_image(flat, ron, gain, blevel); 01044 } 01045 cpl_image_add(master_flat, flat); 01046 cpl_image_delete(flat); flat = NULL; 01047 } 01048 else 01049 fors_pmos_calib_exit("Cannot load flat field"); 01050 } 01051 01052 /*** 01053 if (nflats > 1) 01054 cpl_image_divide_scalar(master_flat, nflats); 01055 ***/ 01056 01057 } 01058 else { 01059 cpl_imagelist *flatlist = NULL; 01060 double rflux, flux; 01061 01062 added_flat = cpl_image_duplicate(master_flat); 01063 01064 flatlist = cpl_imagelist_new(); 01065 cpl_imagelist_set(flatlist, master_flat, 01066 cpl_imagelist_get_size(flatlist)); 01067 01068 /* 01069 * Stacking with rejection requires normalization 01070 * at the same flux. We normalise according to mean 01071 * flux. This is equivalent to determining the 01072 * flux ratio for each image as the average of the 01073 * flux ratio of all pixels weighted on the actual 01074 * flux of each pixel. 01075 */ 01076 01077 rflux = cpl_image_get_mean(master_flat); 01078 01079 for (i = 1; i < nflats; i++) { 01080 flat = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01081 if (flat) { 01082 if (doit) { 01083 mos_randomise_image(flat, ron, gain, blevel); 01084 } 01085 cpl_image_add(added_flat, flat); 01086 flux = cpl_image_get_mean(flat); 01087 cpl_image_multiply_scalar(flat, rflux / flux); 01088 cpl_imagelist_set(flatlist, flat, 01089 cpl_imagelist_get_size(flatlist)); 01090 } 01091 else { 01092 fors_pmos_calib_exit("Cannot load flat field"); 01093 } 01094 } 01095 01096 if (strcmp(stack_method, "median") == 0) { 01097 master_flat = cpl_imagelist_collapse_median_create(flatlist); 01098 } 01099 01100 if (strcmp(stack_method, "minmax") == 0) { 01101 master_flat = cpl_imagelist_collapse_minmax_create(flatlist, 01102 min_reject, 01103 max_reject); 01104 } 01105 01106 if (strcmp(stack_method, "ksigma") == 0) { 01107 master_flat = mos_ksigma_stack(flatlist, 01108 klow, khigh, kiter, NULL); 01109 } 01110 } 01111 } 01112 01113 01114 /* 01115 * Get the reference wavelength and the rebin factor along the 01116 * dispersion direction from the arc lamp exposure 01117 */ 01118 01119 header = dfs_load_header(frameset, arc_tag, 0); 01120 01121 if (header == NULL) 01122 fors_pmos_calib_exit("Cannot load arc lamp header"); 01123 01124 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 01125 if (instrume == NULL) 01126 fors_pmos_calib_exit("Missing keyword INSTRUME in arc lamp header"); 01127 01128 instrume = cpl_strdup(instrume); 01129 01130 if (instrume[4] == '1') 01131 snprintf(version, 80, "%s/%s", "fors1", VERSION); 01132 if (instrume[4] == '2') 01133 snprintf(version, 80, "%s/%s", "fors2", VERSION); 01134 01135 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 01136 01137 if (cpl_error_get_code() != CPL_ERROR_NONE) 01138 fors_pmos_calib_exit("Missing keyword ESO INS GRIS1 WLEN in arc lamp " 01139 "frame header"); 01140 01141 if (reference < 3000.0) /* Perhaps in nanometers... */ 01142 reference *= 10; 01143 01144 if (reference < 3000.0 || reference > 13000.0) { 01145 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 01146 "keyword ESO INS GRIS1 WLEN in arc lamp frame header", 01147 reference); 01148 fors_pmos_calib_exit(NULL); 01149 } 01150 01151 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 01152 01153 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 01154 01155 if (cpl_error_get_code() != CPL_ERROR_NONE) 01156 fors_pmos_calib_exit("Missing keyword ESO DET WIN1 BINX in arc lamp " 01157 "frame header"); 01158 01159 if (rebin != 1) { 01160 dispersion *= rebin; 01161 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01162 "working dispersion used is %f A/pixel", rebin, 01163 dispersion); 01164 } 01165 01166 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01167 01168 if (cpl_error_get_code() != CPL_ERROR_NONE) 01169 fors_pmos_calib_exit("Missing keyword ESO DET OUT1 CONAD in arc lamp " 01170 "frame header"); 01171 01172 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 01173 01174 if (pmos) { 01175 int nslits_out_det; 01176 cpl_msg_info(recipe, "Produce mask slit position table..."); 01177 01178 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det); 01179 01180 /* 01181 * Check if all slits have the same X offset: in such case, 01182 * treat the observation as a long-slit one! 01183 */ 01184 01185 mxpos = cpl_table_get_column_median(maskslits, "xtop"); 01186 xpos = cpl_table_get_data_double(maskslits, "xtop"); 01187 nslits = cpl_table_get_nrow(maskslits); 01188 01189 same_offset = 1; 01190 for (i = 0; i < nslits; i++) { 01191 if (fabs(mxpos-xpos[i]) > 0.01) { 01192 same_offset = 0; 01193 break; 01194 } 01195 } 01196 //If not all the slits are illuminated, then we cannot say that 01197 //all have the same offsets. 01198 if(nslits_out_det != 0) 01199 same_offset = 0; 01200 01201 if (same_offset) { 01202 cpl_msg_info(recipe, "All slits have same offset: %.2f", mxpos); 01203 } 01204 else { 01205 cpl_msg_info(recipe, "All slits have different offsets"); 01206 } 01207 01208 if (ny != 400 && ny != 500) { 01209 if (cpl_frameset_count_tags(frameset, 01210 master_distortion_tag) == 0) 01211 fors_pmos_calib_exit( 01212 "Missing required input: MASTER_DISTORTION_TABLE"); 01213 01214 header_dist = dfs_load_header(frameset, 01215 master_distortion_tag, 0); 01216 rebin_dist = cpl_propertylist_get_int(header_dist, 01217 "ESO DET WIN1 BINX"); 01218 cpl_propertylist_delete(header_dist); 01219 } 01220 } 01221 01222 /* Leave the header on for the next step... */ 01223 01224 01225 /* 01226 * Remove the master bias 01227 */ 01228 01229 if (nbias) { 01230 01231 /* 01232 * Set of raw BIASes in input, need to create master bias! 01233 */ 01234 01235 cpl_msg_info(recipe, "Generate the master from input raw biases..."); 01236 01237 if (nbias > 1) { 01238 01239 biases = cpl_imagelist_new(); 01240 01241 bias = dfs_load_image(frameset, "BIAS", CPL_TYPE_FLOAT, 0, 0); 01242 01243 if (bias == NULL) 01244 fors_pmos_calib_exit("Cannot load bias frame"); 01245 01246 cpl_imagelist_set(biases, bias, 0); 01247 01248 for (i = 1; i < nbias; i++) { 01249 bias = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01250 if (bias) 01251 cpl_imagelist_set(biases, bias, i); 01252 else 01253 fors_pmos_calib_exit("Cannot load bias frame"); 01254 } 01255 01256 master_bias = cpl_imagelist_collapse_median_create(biases); 01257 01258 cpl_imagelist_delete(biases); 01259 } 01260 else { 01261 master_bias = dfs_load_image(frameset, "BIAS", 01262 CPL_TYPE_FLOAT, 0, 1); 01263 if (master_bias == NULL) 01264 fors_pmos_calib_exit("Cannot load bias"); 01265 } 01266 01267 } 01268 else { 01269 master_bias = dfs_load_image(frameset, "MASTER_BIAS", 01270 CPL_TYPE_FLOAT, 0, 1); 01271 if (master_bias == NULL) 01272 fors_pmos_calib_exit("Cannot load master bias"); 01273 } 01274 01275 cpl_msg_info(recipe, "Remove the master bias..."); 01276 01277 overscans = mos_load_overscans_fors(header); 01278 cpl_propertylist_delete(header); header = NULL; 01279 01280 if (nbias) { 01281 int xlow = cpl_table_get_int(overscans, "xlow", 0, NULL); 01282 int ylow = cpl_table_get_int(overscans, "ylow", 0, NULL); 01283 int xhig = cpl_table_get_int(overscans, "xhig", 0, NULL); 01284 int yhig = cpl_table_get_int(overscans, "yhig", 0, NULL); 01285 dummy = cpl_image_extract(master_bias, xlow+1, ylow+1, xhig, yhig); 01286 cpl_image_delete(master_bias); master_bias = dummy; 01287 01288 if (dfs_save_image(frameset, master_bias, "MASTER_BIAS", 01289 NULL, parlist, recipe, version)) 01290 fors_pmos_calib_exit(NULL); 01291 } 01292 01293 if (nflats > 1) { 01294 multi_bias = cpl_image_multiply_scalar_create(master_bias, nflats); 01295 dummy = mos_remove_bias(master_flat, multi_bias, overscans); 01296 if (added_flat) 01297 add_dummy = mos_remove_bias(added_flat, multi_bias, overscans); 01298 cpl_image_delete(multi_bias); 01299 } 01300 else { 01301 dummy = mos_remove_bias(master_flat, master_bias, overscans); 01302 } 01303 cpl_image_delete(master_flat); 01304 master_flat = dummy; 01305 01306 if (master_flat == NULL) 01307 fors_pmos_calib_exit("Cannot remove bias from flat field"); 01308 01309 if (added_flat) { 01310 cpl_image_delete(added_flat); 01311 added_flat = add_dummy; 01312 01313 if (added_flat == NULL) 01314 fors_pmos_calib_exit("Cannot remove bias from added flat field"); 01315 01316 trace_flat = added_flat; 01317 } 01318 else 01319 trace_flat = master_flat; 01320 01321 wavelengths = dfs_load_table(frameset, "MASTER_LINECAT", 1); 01322 01323 if (wavelengths == NULL) 01324 fors_pmos_calib_exit("Cannot load line catalog"); 01325 01326 /* 01327 * Cast the wavelengths into a (double precision) CPL vector 01328 */ 01329 01330 nlines = cpl_table_get_nrow(wavelengths); 01331 01332 if (nlines == 0) 01333 fors_pmos_calib_exit("Empty input line catalog"); 01334 01335 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 01336 cpl_msg_error(recipe, "Missing column %s in input line catalog table", 01337 wcolumn); 01338 fors_pmos_calib_exit(NULL); 01339 } 01340 01341 line = cpl_malloc(nlines * sizeof(double)); 01342 01343 for (i = 0; i < nlines; i++) 01344 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 01345 01346 lines = cpl_vector_wrap(nlines, line); 01347 01348 for (j = 0; j < pmos; j++) { 01349 int k; 01350 01351 cpl_msg_indent_less(); 01352 cpl_msg_info(recipe, "Processing arc lamp nb %d out of %d ...", 01353 j + 1, pmos); 01354 cpl_msg_indent_more(); 01355 01356 cpl_msg_info(recipe, "Load arc lamp exposure..."); 01357 cpl_msg_indent_more(); 01358 01359 spectra = dfs_load_image(frameset, arc_tag, CPL_TYPE_FLOAT, 0, 0); 01360 01361 /* 01362 * FIXME: Horrible workaround to avoid the problem because of the 01363 * multiple encapsulation of cpl_frameset_find() in different 01364 * loading functions 01365 */ 01366 for (k = 0; k < j; k ++) { 01367 cpl_image_delete(spectra); 01368 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01369 } 01370 01371 if (spectra == NULL) 01372 fors_pmos_calib_exit("Cannot load arc lamp exposure"); 01373 01374 if (doit) { 01375 mos_randomise_image(spectra, ron, gain, blevel); 01376 } 01377 01378 cpl_msg_info(recipe, "Remove the master bias..."); 01379 01380 dummy = mos_remove_bias(spectra, master_bias, overscans); 01381 cpl_image_delete(spectra); spectra = dummy; 01382 01383 if (spectra == NULL) 01384 fors_pmos_calib_exit("Cannot remove bias from arc lamp exposure"); 01385 01386 cpl_msg_indent_less(); 01387 cpl_msg_info(recipe, "Load input line catalog..."); 01388 cpl_msg_indent_more(); 01389 01390 /* 01391 * Here the PMOS calibration is carried out. 01392 */ 01393 01394 if (mos_saturation_process(spectra)) 01395 fors_pmos_calib_exit("Cannot process saturation"); 01396 01397 if (mos_subtract_background(spectra)) 01398 fors_pmos_calib_exit("Cannot subtract the background"); 01399 01400 if (!j) { 01401 /* 01402 * Detecting spectra on the CCD 01403 */ 01404 01405 cpl_msg_indent_less(); 01406 cpl_msg_info(recipe, "Detecting spectra on CCD..."); 01407 cpl_msg_indent_more(); 01408 01409 ccd_xsize = nx = cpl_image_get_size_x(spectra); 01410 ccd_ysize = ny = cpl_image_get_size_y(spectra); 01411 01412 refmask = cpl_mask_new(nx, ny); 01413 01414 checkwave = 01415 mos_wavelength_calibration_raw(spectra, lines, dispersion, 01416 peakdetection, wradius, 01417 wdegree, wreject, reference, 01418 &startwavelength, &endwavelength, 01419 NULL, NULL, NULL, NULL, NULL, 01420 NULL, refmask); 01421 01422 if (checkwave == NULL) 01423 fors_pmos_calib_exit("Wavelength calibration failure."); 01424 01425 /* 01426 * Save check image to disk 01427 */ 01428 01429 header = cpl_propertylist_new(); 01430 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01431 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01432 cpl_propertylist_update_double(header, "CRVAL1", 01433 startwavelength + dispersion/2); 01434 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01435 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01436 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01437 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01438 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01439 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01440 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01441 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01442 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01443 01444 if (check) { 01445 if (!j) { 01446 if(dfs_save_image_null(frameset, parlist, 01447 spectra_detection_tag, 01448 recipe, version)) { 01449 fors_pmos_calib_exit(NULL); 01450 } 01451 } 01452 01453 if (dfs_save_image_ext(checkwave, 01454 spectra_detection_tag, header)) { 01455 fors_pmos_calib_exit(NULL); 01456 } 01457 } 01458 01459 cpl_image_delete(checkwave); checkwave = NULL; 01460 cpl_propertylist_delete(header); header = NULL; 01461 01462 if (cpl_mask_is_empty(refmask)) 01463 fors_pmos_calib_exit("Wavelength calibration failure."); 01464 01465 if (mos_refmask_find_gaps(refmask, trace_flat, -1.0)) 01466 fors_pmos_calib_exit("The gaps could not be found"); 01467 01468 cpl_msg_info(recipe, 01469 "Locate slits at reference wavelength on CCD..."); 01470 slits = mos_locate_spectra(refmask); 01471 01472 if (!slits) { 01473 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 01474 fors_pmos_calib_exit("No slits could be detected!"); 01475 } 01476 01477 if (same_offset) { 01478 if (ny != 400 && ny != 500) { 01479 float rescale = (float) rebin_dist / rebin; 01480 if (mos_check_slits(slits, rescale)) { 01481 fors_pmos_calib_exit("Some slits are missing. " 01482 "Cannot recover!"); 01483 } 01484 } 01485 } 01486 01487 refimage = cpl_image_new_from_mask(refmask); 01488 cpl_mask_delete(refmask); refmask = NULL; 01489 01490 if (check) { 01491 if (!j) { 01492 if(dfs_save_image_null(frameset, parlist, 01493 slit_map_tag, 01494 recipe, version)) { 01495 fors_pmos_calib_exit(NULL); 01496 } 01497 } 01498 01499 save_header = dfs_load_header(frameset, arc_tag, 0); 01500 01501 for (k = 0; k < j; k ++) { 01502 cpl_propertylist_delete(save_header); 01503 save_header = dfs_load_header(frameset, NULL, 0); 01504 } 01505 01506 if (dfs_save_image_ext(refimage, slit_map_tag, save_header)) { 01507 fors_pmos_calib_exit(NULL); 01508 } 01509 cpl_propertylist_delete(save_header); save_header = NULL; 01510 } 01511 01512 cpl_image_delete(refimage); refimage = NULL; 01513 01514 // if (same_offset == 0) { 01515 01516 same_offset = 1; // Added, see next line comment. 01517 if (0) { // This part is eliminated: a successful 01518 // pattern matching would identify just 01519 // one of the two beams!!! It needs to be FIXED. 01520 01521 /* 01522 * Attempt slit identification: this recipe may continue even 01523 * in case of failed identification (i.e., the position table 01524 * is not produced, but an error is not set). In case of 01525 * failure, the spectra would be still extracted, even if they 01526 * would not be associated to slits on the mask. 01527 * 01528 * The reason for making the slit identification an user option 01529 * (via the parameter slit_ident) is to offer the possibility 01530 * to avoid identifications that are only apparently successful 01531 * as it would happen in the case of an incorrect slit 01532 * description in the data header. 01533 */ 01534 01535 cpl_msg_indent_less(); 01536 cpl_msg_info(recipe, 01537 "Attempt slit identification (optional)..."); 01538 cpl_msg_indent_more(); 01539 01540 positions = mos_identify_slits(slits, maskslits, NULL); 01541 01542 if (positions) { 01543 cpl_table_delete(slits); 01544 slits = positions; 01545 01546 /* 01547 * Eliminate slits which are not _entirely_ inside the CCD 01548 */ 01549 01550 cpl_table_and_selected_double(slits, 01551 "ytop", CPL_GREATER_THAN, ny); 01552 cpl_table_or_selected_double(slits, 01553 "ybottom", CPL_LESS_THAN, 0); 01554 cpl_table_erase_selected(slits); 01555 01556 nslits = cpl_table_get_nrow(slits); 01557 01558 if (nslits == 0) 01559 fors_pmos_calib_exit("No slits found on the CCD"); 01560 01561 cpl_msg_info(recipe, 01562 "%d slits are entirely contained in CCD", 01563 nslits); 01564 } 01565 else { 01566 same_offset = 1; /* FIXLANDER slit_ident = 0; */ 01567 cpl_msg_info(recipe, 01568 "Global distortion model cannot be computed"); 01569 if (cpl_error_get_code() != CPL_ERROR_NONE) { 01570 fors_pmos_calib_exit(NULL); 01571 } 01572 } 01573 } 01574 01575 01576 if (ny == 400 || ny == 500) { 01577 01578 /* 01579 * For the FORS1 special case (old chip 2048x400 readout) 01580 * keep the central slits only 01581 */ 01582 01583 nslits = cpl_table_get_nrow(slits); 01584 01585 if (nslits > 4) { 01586 cpl_table_unselect_all(slits); 01587 for (k = 0; k < cpl_table_get_nrow(slits); k++) { 01588 double jump = cpl_table_get(slits, "ytop", k, NULL) 01589 - cpl_table_get(slits, "ybottom", k, NULL); 01590 if (jump < 50.) { 01591 cpl_table_select_row(slits, k); 01592 } 01593 } 01594 cpl_table_erase_selected(slits); 01595 nslits = cpl_table_get_nrow(slits); 01596 } 01597 01598 if (nslits == 0) 01599 fors_pmos_calib_exit("No slits found on the CCD"); 01600 01601 if (nslits == 4) { 01602 cpl_table_unselect_all(slits); 01603 cpl_table_select_row(slits, 0); 01604 cpl_table_select_row(slits, cpl_table_get_nrow(slits)-1); 01605 cpl_table_erase_selected(slits); 01606 } 01607 01608 cpl_msg_info(recipe, 01609 "%d slits are entirely contained in CCD", nslits); 01610 } 01611 else { 01612 cpl_table_unselect_all(slits); 01613 for (k = 0; k < cpl_table_get_nrow(slits); k++) { 01614 double jump = cpl_table_get(slits, "ytop", k, NULL) 01615 - cpl_table_get(slits, "ybottom", k, NULL); 01616 if (jump < 10.) { 01617 cpl_table_select_row(slits, k); 01618 } 01619 } 01620 cpl_table_erase_selected(slits); 01621 nslits = cpl_table_get_nrow(slits); 01622 } 01623 01624 01625 /* 01626 * Determination of spectral curvature 01627 */ 01628 01629 cpl_msg_indent_less(); 01630 cpl_msg_info(recipe, "Determining spectral curvature..."); 01631 cpl_msg_indent_more(); 01632 01633 cpl_msg_info(recipe, "Tracing master flat field spectra edges..."); 01634 traces = mos_trace_flat(trace_flat, slits, reference, 01635 startwavelength, endwavelength, dispersion); 01636 01637 if (!traces) 01638 fors_pmos_calib_exit("Tracing failure"); 01639 01640 cpl_image_delete(added_flat); added_flat = NULL; 01641 01642 cpl_msg_info(recipe, "Fitting flat field spectra edges..."); 01643 polytraces = mos_poly_trace(slits, traces, cdegree); 01644 01645 if (!polytraces) 01646 fors_pmos_calib_exit("Trace fitting failure"); 01647 01648 if (cmode) { 01649 cpl_msg_info(recipe, 01650 "Computing global spectral curvature model..."); 01651 mos_global_trace(slits, polytraces, cmode); 01652 } 01653 01654 if (!j) { 01655 if(dfs_save_image_null(frameset, parlist, curv_traces_tag, 01656 recipe, version)) { 01657 fors_pmos_calib_exit(NULL); 01658 } 01659 } 01660 01661 if (dfs_save_table_ext(traces, curv_traces_tag, NULL)) { 01662 fors_pmos_calib_exit(NULL); 01663 } 01664 01665 cpl_table_delete(traces); traces = NULL; 01666 01667 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01668 01669 } 01670 // 01671 spatial = mos_spatial_calibration(spectra, slits, polytraces, 01672 reference, 01673 startwavelength, endwavelength, 01674 dispersion, 0, j ? NULL: coordinate); 01675 01676 if (!j) { 01677 // 01678 if (same_offset) { /* FIXLANDER It was !slit_ident */ 01679 cpl_image_delete(spectra); spectra = NULL; 01680 } 01681 01682 /* 01683 * Flat field normalisation is done directly on the master flat 01684 * field (without spatial rectification first). The spectral 01685 * curvature model may be provided in input, in future releases. 01686 */ 01687 01688 cpl_msg_indent_less(); 01689 cpl_msg_info(recipe, "Perform flat field normalisation..."); 01690 cpl_msg_indent_more(); 01691 01692 norm_flat = cpl_image_duplicate(master_flat); 01693 01694 smo_flat = mos_normalise_flat(norm_flat, coordinate, slits, 01695 polytraces, reference, 01696 startwavelength, endwavelength, 01697 dispersion, dradius, ddegree); 01698 01699 /* This may be a product */ 01700 cpl_image_delete(smo_flat); smo_flat = NULL; 01701 01702 01703 save_header = dfs_load_header(frameset, flat_tag, 0); 01704 cpl_propertylist_update_int(save_header, "ESO PRO DATANCOM", 01705 nflats); 01706 01707 rect_flat = mos_spatial_calibration(master_flat, slits, polytraces, 01708 reference, startwavelength, 01709 endwavelength, dispersion, 0, 01710 NULL); 01711 rect_nflat = mos_spatial_calibration(norm_flat, slits, polytraces, 01712 reference, startwavelength, 01713 endwavelength, dispersion, 0, 01714 NULL); 01715 01716 01717 if (dfs_save_image(frameset, master_flat, master_screen_flat_tag, 01718 save_header, parlist, recipe, version)) 01719 fors_pmos_calib_exit(NULL); 01720 01721 01722 if (dfs_save_image(frameset, norm_flat, master_norm_flat_tag, 01723 save_header, parlist, recipe, version)) 01724 fors_pmos_calib_exit(NULL); 01725 01726 cpl_image_delete(norm_flat); norm_flat = NULL; 01727 cpl_propertylist_delete(save_header); save_header = NULL; 01728 01729 } 01730 01731 01732 /* 01733 * Final wavelength calibration of spectra having their curvature 01734 * removed 01735 */ 01736 01737 cpl_msg_indent_less(); 01738 cpl_msg_info(recipe, "Perform final wavelength calibration..."); 01739 cpl_msg_indent_more(); 01740 01741 nx = cpl_image_get_size_x(spatial); 01742 ny = cpl_image_get_size_y(spatial); 01743 01744 idscoeff = cpl_table_new(ny); 01745 restable = cpl_table_new(nlines); 01746 rainbow = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01747 if (check) 01748 residual = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01749 fiterror = cpl_calloc(ny, sizeof(double)); 01750 fitlines = cpl_calloc(ny, sizeof(int)); 01751 01752 rectified = mos_wavelength_calibration_final(spatial, slits, lines, 01753 dispersion, peakdetection, 01754 wradius, wdegree, wreject, 01755 reference, 01756 &startwavelength, 01757 &endwavelength, fitlines, 01758 fiterror, idscoeff, 01759 rainbow, 01760 residual, restable); 01761 01762 if (rectified == NULL) 01763 fors_pmos_calib_exit("Wavelength calibration failure."); 01764 01765 if (!j) { 01766 if(dfs_save_image_null(frameset, parlist, disp_residuals_table_tag, 01767 recipe, version)) { 01768 fors_pmos_calib_exit(NULL); 01769 } 01770 } 01771 01772 header = dfs_load_header(frameset, arc_tag, 0); 01773 01774 for (k = 0; k < j; k ++) { 01775 cpl_propertylist_delete(header); 01776 header = dfs_load_header(frameset, NULL, 0); 01777 } 01778 01779 if (dfs_save_table_ext(restable, disp_residuals_table_tag, header)) { 01780 fors_pmos_calib_exit(NULL); 01781 } 01782 01783 cpl_propertylist_delete(header); 01784 01785 cpl_table_delete(restable); restable = NULL; 01786 01787 cpl_table_wrap_double(idscoeff, fiterror, "error"); fiterror = NULL; 01788 cpl_table_set_column_unit(idscoeff, "error", "pixel"); 01789 cpl_table_wrap_int(idscoeff, fitlines, "nlines"); fitlines = NULL; 01790 01791 for (i = 0; i < ny; i++) 01792 if (!cpl_table_is_valid(idscoeff, "c0", i)) 01793 cpl_table_set_invalid(idscoeff, "error", i); 01794 01795 delta = mos_map_pixel(idscoeff, reference, startwavelength, 01796 endwavelength, dispersion, 2); 01797 01798 header = dfs_load_header(frameset, arc_tag, 0); 01799 01800 for (k = 0; k < j; k ++) { 01801 cpl_propertylist_delete(header); 01802 header = dfs_load_header(frameset, NULL, 0); 01803 } 01804 01805 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01806 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01807 cpl_propertylist_update_double(header, "CRVAL1", 01808 startwavelength + dispersion/2); 01809 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01810 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01811 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01812 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01813 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01814 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01815 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01816 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01817 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01818 01819 if (!j) { 01820 if(dfs_save_image_null(frameset, parlist, delta_image_tag, 01821 recipe, version)) { 01822 fors_pmos_calib_exit(NULL); 01823 } 01824 } 01825 01826 if (dfs_save_image_ext(delta, delta_image_tag, header)) { 01827 fors_pmos_calib_exit(NULL); 01828 } 01829 01830 cpl_image_delete(delta); delta = NULL; 01831 cpl_propertylist_delete(header); header = NULL; 01832 01833 mean_rms = mos_distortions_rms(rectified, lines, startwavelength, 01834 dispersion, 6, 0); 01835 01836 cpl_msg_info(recipe, "Mean residual: %f pixel", mean_rms); 01837 01838 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01839 mean_rms_err = cpl_table_get_column_stdev(idscoeff, "error"); 01840 01841 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 01842 mean_rms, mean_rms * dispersion); 01843 01844 restab = mos_resolution_table(rectified, startwavelength, dispersion, 01845 60000, lines); 01846 01847 if (restab) { 01848 cpl_msg_info(recipe, "Mean spectral resolution: %.2f", 01849 cpl_table_get_column_mean(restab, "resolution")); 01850 cpl_msg_info(recipe, 01851 "Mean reference lines FWHM: %.2f +/- %.2f pixel", 01852 cpl_table_get_column_mean(restab, "fwhm") / dispersion, 01853 cpl_table_get_column_mean(restab, "fwhm_rms") / dispersion); 01854 01855 cpl_table_duplicate_column(restab, "dlambda", 01856 restab, "fwhm"); 01857 cpl_table_multiply_scalar(restab, "dlambda", dispersion); 01858 cpl_table_duplicate_column(restab, "dlambda_rms", 01859 restab, "fwhm_rms"); 01860 cpl_table_multiply_scalar(restab, "dlambda_rms", dispersion); 01861 01862 if (qc) { 01863 01864 qclist = cpl_propertylist_new(); 01865 01866 /* 01867 * QC1 parameters 01868 */ 01869 keyname = "QC.DID"; 01870 01871 if (fors_header_write_string(qclist, 01872 keyname, 01873 "2.0", 01874 "QC1 dictionary")) { 01875 fors_pmos_calib_exit("Cannot write dictionary version " 01876 "to QC log file"); 01877 } 01878 01879 01880 keyname = "QC.PMOS.RESOLUTION"; 01881 01882 if (fors_header_write_double(qclist, 01883 cpl_table_get_column_mean(restab, 01884 "resolution"), 01885 keyname, 01886 "Angstrom", 01887 "Mean spectral resolution")) { 01888 fors_pmos_calib_exit("Cannot write mean spectral " 01889 "resolution to QC log file"); 01890 } 01891 01892 keyname = "QC.PMOS.RESOLUTION.RMS"; 01893 01894 if (fors_header_write_double(qclist, 01895 cpl_table_get_column_stdev(restab, 01896 "resolution"), 01897 keyname, 01898 "Angstrom", 01899 "Scatter of spectral resolution")) { 01900 fors_pmos_calib_exit("Cannot write spectral resolution " 01901 "scatter to QC log file"); 01902 } 01903 01904 keyname = "QC.PMOS.RESOLUTION.NWAVE"; 01905 01906 if (fors_header_write_int(qclist, cpl_table_get_nrow(restab) - 01907 cpl_table_count_invalid(restab, 01908 "resolution"), 01909 keyname, 01910 NULL, 01911 "Number of examined wavelengths " 01912 "for resolution computation")) { 01913 fors_pmos_calib_exit("Cannot write number of lines used " 01914 "in spectral resolution computation " 01915 "to QC log file"); 01916 } 01917 01918 keyname = "QC.PMOS.RESOLUTION.MEANRMS"; 01919 01920 if (fors_header_write_double(qclist, 01921 cpl_table_get_column_mean(restab, 01922 "resolution_rms"), 01923 keyname, NULL, 01924 "Mean error on spectral " 01925 "resolution computation")) { 01926 fors_pmos_calib_exit("Cannot write mean error in " 01927 "spectral resolution computation " 01928 "to QC log file"); 01929 } 01930 01931 keyname = "QC.PMOS.RESOLUTION.NLINES"; 01932 01933 if (fors_header_write_int(qclist, 01934 cpl_table_get_column_mean(restab, 01935 "nlines") * 01936 cpl_table_get_nrow(restab), 01937 keyname, NULL, 01938 "Number of lines for spectral " 01939 "resolution computation")) { 01940 fors_pmos_calib_exit("Cannot write number of examined " 01941 "wavelengths in spectral resolution " 01942 "computation to QC log file"); 01943 } 01944 01945 } 01946 01947 if (!j) { 01948 if(dfs_save_image_null(frameset, parlist, 01949 spectral_resolution_tag, 01950 recipe, version)) { 01951 fors_pmos_calib_exit(NULL); 01952 } 01953 } 01954 01955 header = dfs_load_header(frameset, arc_tag, 0); 01956 01957 for (k = 0; k < j; k ++) { 01958 cpl_propertylist_delete(header); 01959 header = dfs_load_header(frameset, NULL, 0); 01960 } 01961 01962 cpl_propertylist_append(header, qclist); 01963 01964 if (dfs_save_table_ext(restab, spectral_resolution_tag, header)) { 01965 fors_pmos_calib_exit(NULL); 01966 } 01967 01968 cpl_table_delete(restab); restab = NULL; 01969 cpl_propertylist_delete(qclist); qclist = NULL; 01970 cpl_propertylist_delete(header); header = NULL; 01971 01972 } 01973 else 01974 fors_pmos_calib_exit("Cannot compute the spectral " 01975 "resolution table"); 01976 01977 if (!j) { 01978 if(dfs_save_image_null(frameset, parlist, disp_coeff_tag, 01979 recipe, version)) { 01980 fors_pmos_calib_exit(NULL); 01981 } 01982 } 01983 01984 header = dfs_load_header(frameset, arc_tag, 0); 01985 01986 for (k = 0; k < j; k ++) { 01987 cpl_propertylist_delete(header); 01988 header = dfs_load_header(frameset, NULL, 0); 01989 } 01990 01991 if (dfs_save_table_ext(idscoeff, disp_coeff_tag, header)) { 01992 fors_pmos_calib_exit(NULL); 01993 } 01994 01995 cpl_propertylist_delete(header); 01996 01997 if (!j) { 01998 mapped_flat = mos_wavelength_calibration(rect_flat, reference, 01999 startwavelength, 02000 endwavelength, 02001 dispersion, idscoeff, 0); 02002 02003 mapped_nflat = mos_wavelength_calibration(rect_nflat, reference, 02004 startwavelength, 02005 endwavelength, 02006 dispersion, idscoeff, 0); 02007 02008 cpl_image_delete(rect_flat); rect_flat = NULL; 02009 cpl_image_delete(rect_nflat); rect_nflat = NULL; 02010 } 02011 02012 /* Global removed */ 02013 02014 cpl_table_delete(idscoeff); idscoeff = NULL; 02015 02016 header = dfs_load_header(frameset, arc_tag, 0); 02017 02018 for (k = 0; k < j; k ++) { 02019 cpl_propertylist_delete(header); 02020 header = dfs_load_header(frameset, NULL, 0); 02021 } 02022 02023 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 02024 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 02025 cpl_propertylist_update_double(header, "CRVAL1", 02026 startwavelength + dispersion/2); 02027 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02028 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02029 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02030 cpl_propertylist_update_double(header, "CD1_1", dispersion); 02031 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02032 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02033 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02034 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02035 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02036 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", 1); 02037 02038 if (!j) { 02039 if(dfs_save_image_null(frameset, parlist, reduced_lamp_tag, 02040 recipe, version)) { 02041 fors_pmos_calib_exit(NULL); 02042 } 02043 } 02044 02045 if (dfs_save_image_ext(rectified, reduced_lamp_tag, header)) { 02046 fors_pmos_calib_exit(NULL); 02047 } 02048 02049 cpl_image_delete(rectified); rectified = NULL; 02050 02051 cpl_propertylist_update_int(header, "ESO PRO DATANCOM", nflats); 02052 02053 if (!j) { 02054 if (dfs_save_image(frameset, mapped_flat, mapped_screen_flat_tag, 02055 header, parlist, recipe, version)) 02056 fors_pmos_calib_exit(NULL); 02057 cpl_image_delete(mapped_flat); mapped_flat = NULL; 02058 02059 if (dfs_save_image(frameset, mapped_nflat, mapped_norm_flat_tag, 02060 header, parlist, recipe, version)) 02061 fors_pmos_calib_exit(NULL); 02062 cpl_image_delete(mapped_nflat); mapped_nflat = NULL; 02063 } 02064 02065 cpl_propertylist_delete(header); header = NULL; 02066 02067 if (check) { 02068 save_header = dfs_load_header(frameset, arc_tag, 0); 02069 for (k = 0; k < j; k ++) { 02070 cpl_propertylist_delete(save_header); 02071 save_header = dfs_load_header(frameset, NULL, 0); 02072 } 02073 02074 cpl_propertylist_update_double(save_header, "CRPIX2", 1.0); 02075 cpl_propertylist_update_double(save_header, "CRVAL2", 1.0); 02076 /* cpl_propertylist_update_double(save_header, "CDELT2", 1.0); */ 02077 cpl_propertylist_update_double(save_header, "CD1_1", 1.0); 02078 cpl_propertylist_update_double(save_header, "CD1_2", 0.0); 02079 cpl_propertylist_update_double(save_header, "CD2_1", 0.0); 02080 cpl_propertylist_update_double(save_header, "CD2_2", 1.0); 02081 cpl_propertylist_update_string(save_header, "CTYPE1", "LINEAR"); 02082 cpl_propertylist_update_string(save_header, "CTYPE2", "PIXEL"); 02083 02084 if (!j) { 02085 if(dfs_save_image_null(frameset, parlist, disp_residuals_tag, 02086 recipe, version)) { 02087 fors_pmos_calib_exit(NULL); 02088 } 02089 } 02090 02091 if (dfs_save_image_ext(residual, disp_residuals_tag, save_header)) { 02092 fors_pmos_calib_exit(NULL); 02093 } 02094 02095 cpl_image_delete(residual); residual = NULL; 02096 cpl_propertylist_delete(save_header); save_header = NULL; 02097 } 02098 02099 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, polytraces, 02100 reference, startwavelength, endwavelength, 02101 dispersion); 02102 02103 cpl_image_delete(rainbow); rainbow = NULL; 02104 02105 save_header = dfs_load_header(frameset, arc_tag, 0); 02106 02107 for (k = 0; k < j; k ++) { 02108 cpl_propertylist_delete(save_header); 02109 save_header = dfs_load_header(frameset, NULL, 0); 02110 } 02111 02112 if (qc) { 02113 02114 /* 02115 * QC1 parameters 02116 */ 02117 if (fors_header_write_string(save_header, 02118 "QC.DID", 02119 "2.0", 02120 "QC1 dictionary")) { 02121 fors_pmos_calib_exit("Cannot write dictionary version " 02122 "to QC log file"); 02123 } 02124 02125 if (fors_header_write_double(save_header, 02126 mean_rms, 02127 "QC.WAVE.ACCURACY", 02128 "pixel", 02129 "Mean accuracy of wavecalib model")) { 02130 fors_pmos_calib_exit("Cannot write mean wavelength calibration " 02131 "accuracy to QC log file"); 02132 } 02133 02134 02135 if (fors_header_write_double(save_header, 02136 mean_rms_err, 02137 "QC.WAVE.ACCURACY.ERROR", 02138 "pixel", 02139 "Error on accuracy of wavecalib model")) { 02140 fors_pmos_calib_exit("Cannot write error on wavelength " 02141 "calibration accuracy to QC log file"); 02142 } 02143 02144 if (same_offset && fabs(mxpos) < 0.05) { 02145 /* Only if same offset is 0.0 */ 02146 02147 data = cpl_image_get_data(wavemap); 02148 02149 if (fors_header_write_double(save_header, 02150 data[nx/2 + ccd_ysize*nx/2], 02151 "QC.PMOS.CENTRAL.WAVELENGTH", 02152 "Angstrom", 02153 "Wavelength at CCD center")) { 02154 fors_pmos_calib_exit("Cannot write central wavelength " 02155 "to QC log file"); 02156 } 02157 } 02158 02159 } 02160 02161 if (!j) { 02162 if(dfs_save_image_null(frameset, parlist, wavelength_map_tag, 02163 recipe, version)) { 02164 fors_pmos_calib_exit(NULL); 02165 } 02166 } 02167 02168 if (dfs_save_image_ext(wavemap, wavelength_map_tag, save_header)) { 02169 fors_pmos_calib_exit(NULL); 02170 } 02171 02172 cpl_image_delete(wavemap); wavemap = NULL; 02173 02174 cpl_propertylist_erase_regexp(save_header, "^ESO QC ", 0); 02175 02176 cpl_propertylist_delete(save_header); save_header = NULL; 02177 02178 cpl_msg_indent_less(); 02179 02180 } 02181 02182 if (dfs_save_image(frameset, coordinate, spatial_map_tag, save_header, 02183 parlist, recipe, version)) 02184 fors_pmos_calib_exit(NULL); 02185 02186 cpl_image_delete(coordinate); coordinate = NULL; 02187 cpl_propertylist_delete(save_header); save_header = NULL; 02188 02189 header = NULL; 02190 02191 if (qc) { 02192 02193 double maxpos, maxneg, maxcurve, maxslope; 02194 02195 header = dfs_load_header(frameset, arc_tag, 0); 02196 02197 /* 02198 * QC1 parameters 02199 */ 02200 if (fors_header_write_string(header, 02201 "QC.DID", 02202 "2.0", 02203 "QC1 dictionary")) { 02204 fors_pmos_calib_exit("Cannot write dictionary version " 02205 "to QC log file"); 02206 } 02207 02208 maxpos = fabs(cpl_table_get_column_max(polytraces, "c2")); 02209 maxneg = fabs(cpl_table_get_column_min(polytraces, "c2")); 02210 maxcurve = maxpos > maxneg ? maxpos : maxneg; 02211 if (fors_header_write_double(header, 02212 maxcurve, 02213 "QC.TRACE.MAX.CURVATURE", 02214 "Y pixel / X pixel ^2", 02215 "Max observed curvature " 02216 "in spectral tracing")) { 02217 fors_pmos_calib_exit("Cannot write max observed curvature in " 02218 "spectral tracing to QC log file"); 02219 } 02220 02221 maxpos = fabs(cpl_table_get_column_max(polytraces, "c1")); 02222 maxneg = fabs(cpl_table_get_column_min(polytraces, "c1")); 02223 maxslope = maxpos > maxneg ? maxpos : maxneg; 02224 02225 if (fors_header_write_double(header, 02226 maxslope, 02227 "QC.TRACE.MAX.SLOPE", 02228 "Y pixel / X pixel", 02229 "Max observed slope in spectral tracing")) { 02230 fors_pmos_calib_exit("Cannot write max observed slope in spectral " 02231 "tracing to QC log file"); 02232 } 02233 } 02234 02235 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, header, 02236 parlist, recipe, version)) { 02237 fors_pmos_calib_exit(NULL); 02238 } 02239 02240 cpl_propertylist_delete(header); header = NULL; 02241 cpl_table_delete(polytraces); polytraces = NULL; 02242 02243 /* FIXLANDER It was slit_ident == 0 and 02244 it was in a different place above in the code */ 02245 02246 if (same_offset) { 02247 cpl_table *globaltbl; 02248 cpl_table *slitpos; 02249 double *l_ytop; 02250 int *l_id; 02251 int npairs; 02252 double *ytop = cpl_table_get_data_double(slits, "ytop"); 02253 double *ybot = cpl_table_get_data_double(slits, "ybottom"); 02254 int k; 02255 // int *p_id; 02256 02257 /* Just in case it has been modified */ 02258 nslits = cpl_table_get_nrow(slits); 02259 02260 cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT); 02261 // p_id = cpl_table_get_data_int(slits, "pair_id"); 02262 02263 if (ccd_ysize == 400 || ccd_ysize == 500) { 02264 02265 /* 02266 * Special case with old FORS1 chip 02267 */ 02268 02269 l_ytop = cpl_malloc(sizeof(double)); 02270 l_ytop[0] = 255.0; 02271 l_id = cpl_malloc(sizeof(double)); 02272 l_id[0] = 10; 02273 npairs = 1; 02274 } 02275 else { 02276 globaltbl = dfs_load_table(frameset, master_distortion_tag, 1); 02277 slitpos = mos_build_slit_location(globaltbl, maskslits, ccd_ysize); 02278 l_ytop = cpl_table_get_data_double(slitpos, "ytop"); 02279 l_id = cpl_table_get_data_int(slitpos, "slit_id"); 02280 npairs = cpl_table_get_nrow(slitpos); 02281 if (rebin_dist != rebin) { 02282 float rescale = (float)rebin_dist / rebin; 02283 for (i = 0; i < npairs; i++) { 02284 l_ytop[i] *= rescale; 02285 } 02286 } 02287 } 02288 02289 for (k = 0; k < npairs; k++) { 02290 int h; 02291 02292 for (h = 0; h < nslits; h++) { 02293 02294 if (l_ytop[k] < ytop[h] && l_ytop[k] > ybot[h]) { 02295 if (h + 1 < nslits) { 02296 cpl_table_set_int(slits, "pair_id", h, l_id[k]); 02297 cpl_table_set_int(slits, "pair_id", h + 1, l_id[k]); 02298 } 02299 } 02300 } 02301 } 02302 02303 /* %%% */ 02304 02305 cpl_table_fill_invalid_int(slits, "pair_id", -1); 02306 02307 if (ccd_ysize == 400 || ccd_ysize == 500) { 02308 cpl_free(l_ytop); 02309 cpl_free(l_id); 02310 } 02311 else { 02312 cpl_table_delete(slitpos); slitpos = NULL; 02313 cpl_table_delete(globaltbl); globaltbl = NULL; 02314 02315 cpl_table_delete(maskslits); maskslits = NULL; 02316 } 02317 } 02318 02319 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 02320 parlist, recipe, version)) { 02321 fors_pmos_calib_exit(NULL); 02322 } 02323 02324 cpl_table_delete(slits); slits = NULL; 02325 02326 cpl_image_delete(spatial); spatial = NULL; 02327 02328 cpl_free(instrume); instrume = NULL; 02329 02330 cpl_table_delete(overscans); overscans = NULL; 02331 cpl_image_delete(master_bias); master_bias = NULL; 02332 cpl_image_delete(master_flat); master_flat = NULL; 02333 02334 cpl_table_delete(wavelengths); wavelengths = NULL; 02335 cpl_vector_delete(lines); lines = NULL; 02336 02337 if (cpl_error_get_code()) { 02338 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 02339 fors_pmos_calib_exit(NULL); 02340 } 02341 02342 return 0; 02343 }