FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_extract.c,v 1.10 2013/02/28 15:14:25 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:14:25 $ 00024 * $Revision: 1.10 $ 00025 * $Name: fors-4_9_20 $ 00026 */ 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <string.h> 00033 #include <math.h> 00034 #include <cpl.h> 00035 #include <moses.h> 00036 #include <fors_dfs.h> 00037 00038 static int fors_extract_create(cpl_plugin *); 00039 static int fors_extract_exec(cpl_plugin *); 00040 static int fors_extract_destroy(cpl_plugin *); 00041 static int fors_extract(cpl_parameterlist *, cpl_frameset *); 00042 00043 static char fors_extract_description[] = 00044 "This recipe is used to reduce scientific spectra using the global\n" 00045 "distortion table created by the recipe fors_calib. The spectra are\n" 00046 "bias subtracted, flat fielded (if a normalised flat field is specified)\n" 00047 "and remapped eliminating the optical distortions. The wavelength calibration\n" 00048 "can be optionally upgraded using a number of sky lines: if no sky lines\n" 00049 "catalog of wavelengths is specified, an internal one is used instead.\n" 00050 "If the alignment to the sky lines is performed, the applied dispersion\n" 00051 "coefficient table is upgraded and saved to disk, and a new CCD wavelengths\n" 00052 "map is created.\n" 00053 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n" 00054 "depending on the instrument mode, and in particular on the grism used)\n" 00055 "may also be specified: this table contains a default recipe parameter\n" 00056 "setting to control the way spectra are extracted for a specific instrument\n" 00057 "mode, as it is used for automatic run of the pipeline on Paranal and in\n" 00058 "Garching. If this table is specified, it will modify the default recipe\n" 00059 "parameter setting, with the exception of those parameters which have been\n" 00060 "explicitly modifyed on the command line. If a grism table is not specified,\n" 00061 "the input recipe parameters values will always be read from the command\n" 00062 "line, or from an esorex configuration file if present, or from their\n" 00063 "generic default values (that are rarely meaningful).\n" 00064 "In the table below the MXU acronym can be read alternatively as MOS\n" 00065 "and LSS, depending on the instrument mode of the input data. Either a\n" 00066 "scientific or a standard star exposure can be specified in input (not\n" 00067 "both).\n\n" 00068 "Input files:\n\n" 00069 " DO category: Type: Explanation: Required:\n" 00070 " SCIENCE_MXU Raw Scientific exposure Y\n" 00071 " or STANDARD_MXU Raw Standard star exposure Y\n" 00072 " MASTER_BIAS Calib Master bias Y\n" 00073 " GRISM_TABLE Calib Grism table .\n" 00074 " MASTER_SKYLINECAT Calib Sky lines catalog .\n" 00075 "\n" 00076 " MASTER_NORM_FLAT_MXU Calib Normalised flat field .\n" 00077 " MASTER_DISTORTION_TABLE Calib Global distortion model .\n" 00078 "\n" 00079 " or, in case of LSS-like MOS/MXU data,\n" 00080 "\n" 00081 " MASTER_NORM_FLAT_LONG_MXU Calib Normalised flat field .\n" 00082 "Output files:\n\n" 00083 " DO category: Data type: Explanation:\n" 00084 " REDUCED_SCI_MXU FITS image Extracted scientific spectra\n" 00085 " REDUCED_SKY_SCI_MXU FITS image Extracted sky spectra\n" 00086 " REDUCED_ERROR_SCI_MXU FITS image Errors on extracted spectra\n" 00087 " UNMAPPED_SCI_MXU FITS image Sky subtracted scientific spectra\n" 00088 " MAPPED_SCI_MXU FITS image Rectified scientific spectra\n" 00089 " MAPPED_ALL_SCI_MXU FITS image Rectified science spectra with sky\n" 00090 " MAPPED_SKY_SCI_MXU FITS image Rectified sky spectra\n" 00091 " UNMAPPED_SKY_SCI_MXU FITS image Sky on CCD\n" 00092 " GLOBAL_SKY_SPECTRUM_MXU FITS table Global sky spectrum\n" 00093 " OBJECT_TABLE_SCI_MXU FITS table Positions of detected objects\n" 00094 "\n" 00095 " Only if the sky-alignment of the wavelength solution is requested:\n" 00096 " SKY_SHIFTS_LONG_SCI_MXU FITS table Sky lines offsets (LSS-like data)\n" 00097 " or SKY_SHIFTS_SLIT_SCI_MXU FITS table Sky lines offsets (MOS-like data)\n" 00098 " DISP_COEFF_SCI_MXU FITS table Upgraded dispersion coefficients\n" 00099 " WAVELENGTH_MAP_SCI_MXU FITS image Upgraded wavelength map\n\n"; 00100 00101 #define fors_extract_exit(message) \ 00102 { \ 00103 if (message) cpl_msg_error(recipe, message); \ 00104 cpl_free(exptime); \ 00105 cpl_free(instrume); \ 00106 cpl_image_delete(dummy); \ 00107 cpl_image_delete(mapped); \ 00108 cpl_image_delete(mapped_sky); \ 00109 cpl_image_delete(mapped_cleaned); \ 00110 cpl_image_delete(skylocalmap); \ 00111 cpl_image_delete(skymap); \ 00112 cpl_image_delete(smapped); \ 00113 cpl_table_delete(offsets); \ 00114 cpl_table_delete(global); \ 00115 cpl_table_delete(sky); \ 00116 cpl_image_delete(bias); \ 00117 cpl_image_delete(spectra); \ 00118 cpl_image_delete(coordinate); \ 00119 cpl_image_delete(norm_flat); \ 00120 cpl_image_delete(rainbow); \ 00121 cpl_image_delete(rectified); \ 00122 cpl_image_delete(wavemap); \ 00123 cpl_propertylist_delete(header); \ 00124 cpl_propertylist_delete(save_header); \ 00125 cpl_table_delete(grism_table); \ 00126 cpl_table_delete(idscoeff); \ 00127 cpl_table_delete(maskslits); \ 00128 cpl_table_delete(overscans); \ 00129 cpl_table_delete(polytraces); \ 00130 cpl_table_delete(slits); \ 00131 cpl_table_delete(wavelengths); \ 00132 cpl_vector_delete(lines); \ 00133 cpl_msg_indent_less(); \ 00134 return -1; \ 00135 } 00136 00137 00138 #define fors_extract_exit_memcheck(message) \ 00139 { \ 00140 if (message) cpl_msg_info(recipe, message); \ 00141 printf("free exptime (%p)\n", exptime); \ 00142 cpl_free(exptime); \ 00143 printf("free instrume (%p)\n", instrume); \ 00144 cpl_free(instrume); \ 00145 printf("free dummy (%p)\n", dummy); \ 00146 cpl_image_delete(dummy); \ 00147 printf("free mapped (%p)\n", mapped); \ 00148 cpl_image_delete(mapped); \ 00149 printf("free mapped_cleaned (%p)\n", mapped_cleaned); \ 00150 cpl_image_delete(mapped_cleaned); \ 00151 printf("free mapped_sky (%p)\n", mapped_sky); \ 00152 cpl_image_delete(mapped_sky); \ 00153 printf("free skylocalmap (%p)\n", skylocalmap); \ 00154 cpl_image_delete(skylocalmap); \ 00155 printf("free skymap (%p)\n", skymap); \ 00156 cpl_image_delete(skymap); \ 00157 printf("free smapped (%p)\n", smapped); \ 00158 cpl_image_delete(smapped); \ 00159 printf("free offsets (%p)\n", offsets); \ 00160 cpl_table_delete(offsets); \ 00161 printf("free global (%p)\n", global); \ 00162 cpl_table_delete(global); \ 00163 printf("free sky (%p)\n", sky); \ 00164 cpl_table_delete(sky); \ 00165 printf("free bias (%p)\n", bias); \ 00166 cpl_image_delete(bias); \ 00167 printf("free spectra (%p)\n", spectra); \ 00168 cpl_image_delete(spectra); \ 00169 printf("free coordinate (%p)\n", coordinate); \ 00170 cpl_image_delete(coordinate); \ 00171 printf("free norm_flat (%p)\n", norm_flat); \ 00172 cpl_image_delete(norm_flat); \ 00173 printf("free rainbow (%p)\n", rainbow); \ 00174 cpl_image_delete(rainbow); \ 00175 printf("free rectified (%p)\n", rectified); \ 00176 cpl_image_delete(rectified); \ 00177 printf("free wavemap (%p)\n", wavemap); \ 00178 cpl_image_delete(wavemap); \ 00179 printf("free header (%p)\n", header); \ 00180 cpl_propertylist_delete(header); \ 00181 printf("free save_header (%p)\n", save_header); \ 00182 cpl_propertylist_delete(save_header); \ 00183 printf("free grism_table (%p)\n", grism_table); \ 00184 cpl_table_delete(grism_table); \ 00185 printf("free idscoeff (%p)\n", idscoeff); \ 00186 cpl_table_delete(idscoeff); \ 00187 printf("free maskslits (%p)\n", maskslits); \ 00188 cpl_table_delete(maskslits); \ 00189 printf("free overscans (%p)\n", overscans); \ 00190 cpl_table_delete(overscans); \ 00191 printf("free polytraces (%p)\n", polytraces); \ 00192 cpl_table_delete(polytraces); \ 00193 printf("free slits (%p)\n", slits); \ 00194 cpl_table_delete(slits); \ 00195 printf("free wavelengths (%p)\n", wavelengths); \ 00196 cpl_table_delete(wavelengths); \ 00197 printf("free lines (%p)\n", lines); \ 00198 cpl_vector_delete(lines); \ 00199 cpl_msg_indent_less(); \ 00200 return 0; \ 00201 } 00202 00203 00215 int cpl_plugin_get_info(cpl_pluginlist *list) 00216 { 00217 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00218 cpl_plugin *plugin = &recipe->interface; 00219 00220 cpl_plugin_init(plugin, 00221 CPL_PLUGIN_API, 00222 FORS_BINARY_VERSION, 00223 CPL_PLUGIN_TYPE_RECIPE, 00224 "fors_extract", 00225 "Extraction of scientific spectra", 00226 fors_extract_description, 00227 "Carlo Izzo", 00228 PACKAGE_BUGREPORT, 00229 "This file is currently part of the FORS Instrument Pipeline\n" 00230 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00231 "This program is free software; you can redistribute it and/or modify\n" 00232 "it under the terms of the GNU General Public License as published by\n" 00233 "the Free Software Foundation; either version 2 of the License, or\n" 00234 "(at your option) any later version.\n\n" 00235 "This program is distributed in the hope that it will be useful,\n" 00236 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00237 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00238 "GNU General Public License for more details.\n\n" 00239 "You should have received a copy of the GNU General Public License\n" 00240 "along with this program; if not, write to the Free Software Foundation,\n" 00241 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00242 fors_extract_create, 00243 fors_extract_exec, 00244 fors_extract_destroy); 00245 00246 cpl_pluginlist_append(list, plugin); 00247 00248 return 0; 00249 } 00250 00251 00262 static int fors_extract_create(cpl_plugin *plugin) 00263 { 00264 cpl_recipe *recipe; 00265 cpl_parameter *p; 00266 00267 00268 /* 00269 * Check that the plugin is part of a valid recipe 00270 */ 00271 00272 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00273 recipe = (cpl_recipe *)plugin; 00274 else 00275 return -1; 00276 00277 /* 00278 * Create the parameters list in the cpl_recipe object 00279 */ 00280 00281 recipe->parameters = cpl_parameterlist_new(); 00282 00283 00284 /* 00285 * Dispersion 00286 */ 00287 00288 p = cpl_parameter_new_value("fors.fors_extract.dispersion", 00289 CPL_TYPE_DOUBLE, 00290 "Resampling step (Angstrom/pixel)", 00291 "fors.fors_extract", 00292 0.0); 00293 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00294 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00295 cpl_parameterlist_append(recipe->parameters, p); 00296 00297 /* 00298 * Sky lines alignment 00299 */ 00300 00301 p = cpl_parameter_new_value("fors.fors_extract.skyalign", 00302 CPL_TYPE_INT, 00303 "Polynomial order for sky lines alignment, " 00304 "or -1 to avoid alignment", 00305 "fors.fors_extract", 00306 0); 00307 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign"); 00308 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00309 cpl_parameterlist_append(recipe->parameters, p); 00310 00311 /* 00312 * Line catalog table column containing the sky reference wavelengths 00313 */ 00314 00315 p = cpl_parameter_new_value("fors.fors_extract.wcolumn", 00316 CPL_TYPE_STRING, 00317 "Name of sky line catalog table column " 00318 "with wavelengths", 00319 "fors.fors_extract", 00320 "WLEN"); 00321 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn"); 00322 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00323 cpl_parameterlist_append(recipe->parameters, p); 00324 00325 /* 00326 * Start wavelength for spectral extraction 00327 */ 00328 00329 p = cpl_parameter_new_value("fors.fors_extract.startwavelength", 00330 CPL_TYPE_DOUBLE, 00331 "Start wavelength in spectral extraction", 00332 "fors.fors_extract", 00333 0.0); 00334 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00335 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00336 cpl_parameterlist_append(recipe->parameters, p); 00337 00338 /* 00339 * End wavelength for spectral extraction 00340 */ 00341 00342 p = cpl_parameter_new_value("fors.fors_extract.endwavelength", 00343 CPL_TYPE_DOUBLE, 00344 "End wavelength in spectral extraction", 00345 "fors.fors_extract", 00346 0.0); 00347 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00348 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00349 cpl_parameterlist_append(recipe->parameters, p); 00350 00351 /* 00352 * Flux conservation 00353 */ 00354 00355 p = cpl_parameter_new_value("fors.fors_extract.flux", 00356 CPL_TYPE_BOOL, 00357 "Apply flux conservation", 00358 "fors.fors_extract", 00359 TRUE); 00360 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux"); 00361 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00362 cpl_parameterlist_append(recipe->parameters, p); 00363 00364 /* 00365 * Apply flat field 00366 */ 00367 00368 p = cpl_parameter_new_value("fors.fors_extract.flatfield", 00369 CPL_TYPE_BOOL, 00370 "Apply flat field", 00371 "fors.fors_extract", 00372 FALSE); 00373 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield"); 00374 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00375 cpl_parameterlist_append(recipe->parameters, p); 00376 00377 /* 00378 * Global sky subtraction 00379 */ 00380 00381 p = cpl_parameter_new_value("fors.fors_extract.skyglobal", 00382 CPL_TYPE_BOOL, 00383 "Subtract global sky spectrum from CCD", 00384 "fors.fors_extract", 00385 FALSE); 00386 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyglobal"); 00387 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00388 cpl_parameterlist_append(recipe->parameters, p); 00389 00390 /* 00391 * Local sky subtraction on extracted spectra 00392 */ 00393 00394 /*** New sky subtraction (search NSS) 00395 p = cpl_parameter_new_value("fors.fors_extract.skymedian", 00396 CPL_TYPE_INT, 00397 "Degree of sky fitting polynomial for " 00398 "sky subtraction from extracted " 00399 "slit spectra (MOS/MXU only, -1 to disable it)", 00400 "fors.fors_extract", 00401 0); 00402 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian"); 00403 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00404 cpl_parameterlist_append(recipe->parameters, p); 00405 ***/ 00406 00407 p = cpl_parameter_new_value("fors.fors_extract.skymedian", 00408 CPL_TYPE_BOOL, 00409 "Sky subtraction from extracted slit spectra", 00410 "fors.fors_extract", 00411 FALSE); 00412 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian"); 00413 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00414 cpl_parameterlist_append(recipe->parameters, p); 00415 00416 /* 00417 * Local sky subtraction on CCD spectra 00418 */ 00419 00420 p = cpl_parameter_new_value("fors.fors_extract.skylocal", 00421 CPL_TYPE_BOOL, 00422 "Sky subtraction from CCD slit spectra", 00423 "fors.fors_extract", 00424 TRUE); 00425 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal"); 00426 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00427 cpl_parameterlist_append(recipe->parameters, p); 00428 00429 /* 00430 * Cosmic rays removal 00431 */ 00432 00433 p = cpl_parameter_new_value("fors.fors_extract.cosmics", 00434 CPL_TYPE_BOOL, 00435 "Eliminate cosmic rays hits (only if global " 00436 "sky subtraction is also requested)", 00437 "fors.fors_extract", 00438 FALSE); 00439 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics"); 00440 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00441 cpl_parameterlist_append(recipe->parameters, p); 00442 00443 /* 00444 * Slit margin 00445 */ 00446 00447 p = cpl_parameter_new_value("fors.fors_extract.slit_margin", 00448 CPL_TYPE_INT, 00449 "Number of pixels to exclude at each slit " 00450 "in object detection and extraction", 00451 "fors.fors_extract", 00452 3); 00453 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin"); 00454 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00455 cpl_parameterlist_append(recipe->parameters, p); 00456 00457 /* 00458 * Extraction radius 00459 */ 00460 00461 p = cpl_parameter_new_value("fors.fors_extract.ext_radius", 00462 CPL_TYPE_INT, 00463 "Maximum extraction radius for detected " 00464 "objects (pixel)", 00465 "fors.fors_extract", 00466 6); 00467 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius"); 00468 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00469 cpl_parameterlist_append(recipe->parameters, p); 00470 00471 /* 00472 * Contamination radius 00473 */ 00474 00475 p = cpl_parameter_new_value("fors.fors_extract.cont_radius", 00476 CPL_TYPE_INT, 00477 "Minimum distance at which two objects " 00478 "of equal luminosity do not contaminate " 00479 "each other (pixel)", 00480 "fors.fors_extract", 00481 0); 00482 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius"); 00483 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00484 cpl_parameterlist_append(recipe->parameters, p); 00485 00486 /* 00487 * Object extraction method 00488 */ 00489 00490 p = cpl_parameter_new_value("fors.fors_extract.ext_mode", 00491 CPL_TYPE_INT, 00492 "Object extraction method: 0 = aperture, " 00493 "1 = Horne optimal extraction", 00494 "fors.fors_extract", 00495 1); 00496 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode"); 00497 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00498 cpl_parameterlist_append(recipe->parameters, p); 00499 00500 /* 00501 * Normalise output by exposure time 00502 */ 00503 00504 p = cpl_parameter_new_value("fors.fors_extract.time_normalise", 00505 CPL_TYPE_BOOL, 00506 "Normalise output spectra by the exposure time", 00507 "fors.fors_extract", 00508 TRUE); 00509 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise"); 00510 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00511 cpl_parameterlist_append(recipe->parameters, p); 00512 00513 return 0; 00514 } 00515 00516 00525 static int fors_extract_exec(cpl_plugin *plugin) 00526 { 00527 cpl_recipe *recipe; 00528 00529 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00530 recipe = (cpl_recipe *)plugin; 00531 else 00532 return -1; 00533 00534 return fors_extract(recipe->parameters, recipe->frames); 00535 } 00536 00537 00546 static int fors_extract_destroy(cpl_plugin *plugin) 00547 { 00548 cpl_recipe *recipe; 00549 00550 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00551 recipe = (cpl_recipe *)plugin; 00552 else 00553 return -1; 00554 00555 cpl_parameterlist_delete(recipe->parameters); 00556 00557 return 0; 00558 } 00559 00560 00570 static int fors_extract(cpl_parameterlist *parlist, cpl_frameset *frameset) 00571 { 00572 00573 const char *recipe = "fors_extract"; 00574 00575 00576 /* 00577 * Input parameters 00578 */ 00579 00580 double dispersion; 00581 int skyalign; 00582 const char *wcolumn; 00583 double startwavelength; 00584 double endwavelength; 00585 int flux; 00586 int flatfield; 00587 int skyglobal; 00588 int skylocal; 00589 int skymedian; 00590 int cosmics; 00591 int slit_margin; 00592 int ext_radius; 00593 int cont_radius; 00594 int ext_mode; 00595 int time_normalise; 00596 00597 00598 /* 00599 * CPL objects 00600 */ 00601 00602 cpl_imagelist *all_science; 00603 cpl_image **images; 00604 00605 cpl_image *bias = NULL; 00606 cpl_image *norm_flat = NULL; 00607 cpl_image *spectra = NULL; 00608 cpl_image *rectified = NULL; 00609 cpl_image *coordinate = NULL; 00610 cpl_image *rainbow = NULL; 00611 cpl_image *mapped = NULL; 00612 cpl_image *mapped_sky = NULL; 00613 cpl_image *mapped_cleaned = NULL; 00614 cpl_image *smapped = NULL; 00615 cpl_image *wavemap = NULL; 00616 cpl_image *skymap = NULL; 00617 cpl_image *skylocalmap = NULL; 00618 cpl_image *dummy = NULL; 00619 00620 cpl_table *grism_table = NULL; 00621 cpl_table *overscans = NULL; 00622 cpl_table *wavelengths = NULL; 00623 cpl_table *idscoeff = NULL; 00624 cpl_table *slits = NULL; 00625 cpl_table *maskslits = NULL; 00626 cpl_table *polytraces = NULL; 00627 cpl_table *offsets = NULL; 00628 cpl_table *sky = NULL; 00629 cpl_table *global = NULL; 00630 00631 cpl_vector *lines = NULL; 00632 00633 cpl_propertylist *header = NULL; 00634 cpl_propertylist *save_header = NULL; 00635 00636 /* 00637 * Auxiliary variables 00638 */ 00639 00640 char version[80]; 00641 char *instrume = NULL; 00642 char *wheel4 = NULL; 00643 const char *science_tag; 00644 const char *master_norm_flat_tag; 00645 const char *disp_coeff_sky_tag; 00646 const char *wavelength_map_sky_tag; 00647 const char *reduced_science_tag; 00648 const char *reduced_sky_tag; 00649 const char *reduced_error_tag; 00650 const char *mapped_science_tag; 00651 const char *unmapped_science_tag; 00652 const char *mapped_science_sky_tag; 00653 const char *mapped_sky_tag; 00654 const char *unmapped_sky_tag; 00655 const char *global_sky_spectrum_tag; 00656 const char *object_table_tag; 00657 const char *skylines_offsets_tag; 00658 const char *global_distortion_tag = "MASTER_DISTORTION_TABLE"; 00659 char *coll; 00660 int mxu, mos, lss; 00661 int nscience; 00662 double *exptime = NULL; 00663 double alltime; 00664 double mean_rms; 00665 int nlines; 00666 int rebin; 00667 double *line; 00668 int nx, ny; 00669 double reference; 00670 double gain; 00671 double ron; 00672 int standard; 00673 int highres; 00674 int narrow = 0; 00675 int i; 00676 00677 00678 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00679 00680 cpl_msg_set_indentation(2); 00681 00682 if (dfs_files_dont_exist(frameset)) 00683 fors_extract_exit(NULL); 00684 00685 /* 00686 * Get configuration parameters 00687 */ 00688 00689 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00690 cpl_msg_indent_more(); 00691 00692 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00693 fors_extract_exit("Too many in input: GRISM_TABLE"); 00694 00695 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00696 00697 dispersion = dfs_get_parameter_double(parlist, 00698 "fors.fors_extract.dispersion", grism_table); 00699 00700 if (dispersion <= 0.0) 00701 fors_extract_exit("Invalid resampling step"); 00702 00703 skyalign = dfs_get_parameter_int(parlist, 00704 "fors.fors_extract.skyalign", NULL); 00705 00706 if (skyalign > 2) 00707 fors_extract_exit("Max polynomial degree for sky alignment is 2"); 00708 00709 wcolumn = dfs_get_parameter_string(parlist, 00710 "fors.fors_extract.wcolumn", NULL); 00711 00712 startwavelength = dfs_get_parameter_double(parlist, 00713 "fors.fors_extract.startwavelength", grism_table); 00714 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00715 fors_extract_exit("Invalid wavelength"); 00716 00717 endwavelength = dfs_get_parameter_double(parlist, 00718 "fors.fors_extract.endwavelength", grism_table); 00719 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00720 fors_extract_exit("Invalid wavelength"); 00721 00722 if (endwavelength - startwavelength <= 0.0) 00723 fors_extract_exit("Invalid wavelength interval"); 00724 00725 flux = dfs_get_parameter_bool(parlist, "fors.fors_extract.flux", NULL); 00726 00727 flatfield = dfs_get_parameter_bool(parlist, "fors.fors_extract.flatfield", 00728 NULL); 00729 00730 skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_extract.skyglobal", 00731 NULL); 00732 skylocal = dfs_get_parameter_bool(parlist, "fors.fors_extract.skylocal", 00733 NULL); 00734 skymedian = dfs_get_parameter_bool(parlist, "fors.fors_extract.skymedian", 00735 NULL); 00736 /* NSS 00737 skymedian = dfs_get_parameter_int(parlist, "fors.fors_extract.skymedian", 00738 NULL); 00739 */ 00740 00741 if (skylocal && skyglobal) 00742 fors_extract_exit("Cannot apply both local and global sky subtraction"); 00743 00744 if (skylocal && skymedian) 00745 fors_extract_exit("Cannot apply sky subtraction both on extracted " 00746 "and non-extracted spectra"); 00747 00748 cosmics = dfs_get_parameter_bool(parlist, 00749 "fors.fors_extract.cosmics", NULL); 00750 00751 if (cosmics) 00752 if (!(skyglobal || skylocal)) 00753 fors_extract_exit("Cosmic rays correction requires " 00754 "either skylocal=true or skyglobal=true"); 00755 00756 slit_margin = dfs_get_parameter_int(parlist, 00757 "fors.fors_extract.slit_margin", 00758 NULL); 00759 if (slit_margin < 0) 00760 fors_extract_exit("Value must be zero or positive"); 00761 00762 ext_radius = dfs_get_parameter_int(parlist, 00763 "fors.fors_extract.ext_radius", 00764 NULL); 00765 if (ext_radius < 0) 00766 fors_extract_exit("Value must be zero or positive"); 00767 00768 cont_radius = dfs_get_parameter_int(parlist, 00769 "fors.fors_extract.cont_radius", 00770 NULL); 00771 if (cont_radius < 0) 00772 fors_extract_exit("Value must be zero or positive"); 00773 00774 ext_mode = dfs_get_parameter_int(parlist, "fors.fors_extract.ext_mode", 00775 NULL); 00776 if (ext_mode < 0 || ext_mode > 1) 00777 fors_extract_exit("Invalid object extraction mode"); 00778 00779 time_normalise = dfs_get_parameter_bool(parlist, 00780 "fors.fors_extract.time_normalise", NULL); 00781 00782 cpl_table_delete(grism_table); grism_table = NULL; 00783 00784 if (cpl_error_get_code()) 00785 fors_extract_exit("Failure getting the configuration parameters"); 00786 00787 00788 /* 00789 * Check input set-of-frames 00790 */ 00791 00792 cpl_msg_indent_less(); 00793 cpl_msg_info(recipe, "Check input set-of-frames:"); 00794 cpl_msg_indent_more(); 00795 00796 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID")) 00797 fors_extract_exit("Input frames are not from the same grism"); 00798 00799 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID")) 00800 fors_extract_exit("Input frames are not from the same filter"); 00801 00802 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID")) 00803 fors_extract_exit("Input frames are not from the same chip"); 00804 00805 mxu = cpl_frameset_count_tags(frameset, "SCIENCE_MXU"); 00806 mos = cpl_frameset_count_tags(frameset, "SCIENCE_MOS"); 00807 lss = cpl_frameset_count_tags(frameset, "SCIENCE_LSS"); 00808 standard = 0; 00809 00810 if (mxu + mos + lss == 0) { 00811 mxu = cpl_frameset_count_tags(frameset, "STANDARD_MXU"); 00812 mos = cpl_frameset_count_tags(frameset, "STANDARD_MOS"); 00813 lss = cpl_frameset_count_tags(frameset, "STANDARD_LSS"); 00814 standard = 1; 00815 } 00816 00817 if (mxu + mos + lss == 0) 00818 fors_extract_exit("Missing input scientific frame"); 00819 00820 nscience = mxu + mos + lss; 00821 00822 if (mxu && mxu < nscience) 00823 fors_extract_exit("Input scientific frames must be of the same type"); 00824 00825 if (mos && mos < nscience) 00826 fors_extract_exit("Input scientific frames must be of the same type"); 00827 00828 if (lss && lss < nscience) 00829 fors_extract_exit("Input scientific frames must be of the same type"); 00830 00831 if (mxu) { 00832 if (standard) { 00833 cpl_msg_info(recipe, "MXU data found"); 00834 science_tag = "STANDARD_MXU"; 00835 reduced_science_tag = "REDUCED_STD_MXU"; 00836 unmapped_science_tag = "UNMAPPED_STD_MXU"; 00837 mapped_science_tag = "MAPPED_STD_MXU"; 00838 mapped_science_sky_tag = "MAPPED_ALL_STD_MXU"; 00839 skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_MXU"; 00840 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_MXU"; 00841 disp_coeff_sky_tag = "DISP_COEFF_STD_MXU"; 00842 mapped_sky_tag = "MAPPED_SKY_STD_MXU"; 00843 unmapped_sky_tag = "UNMAPPED_SKY_STD_MXU"; 00844 object_table_tag = "OBJECT_TABLE_STD_MXU"; 00845 reduced_sky_tag = "REDUCED_SKY_STD_MXU"; 00846 reduced_error_tag = "REDUCED_ERROR_STD_MXU"; 00847 } 00848 else { 00849 cpl_msg_info(recipe, "MXU data found"); 00850 science_tag = "SCIENCE_MXU"; 00851 reduced_science_tag = "REDUCED_SCI_MXU"; 00852 unmapped_science_tag = "UNMAPPED_SCI_MXU"; 00853 mapped_science_tag = "MAPPED_SCI_MXU"; 00854 mapped_science_sky_tag = "MAPPED_ALL_SCI_MXU"; 00855 skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_MXU"; 00856 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_MXU"; 00857 disp_coeff_sky_tag = "DISP_COEFF_SCI_MXU"; 00858 mapped_sky_tag = "MAPPED_SKY_SCI_MXU"; 00859 unmapped_sky_tag = "UNMAPPED_SKY_SCI_MXU"; 00860 object_table_tag = "OBJECT_TABLE_SCI_MXU"; 00861 reduced_sky_tag = "REDUCED_SKY_SCI_MXU"; 00862 reduced_error_tag = "REDUCED_ERROR_SCI_MXU"; 00863 } 00864 00865 master_norm_flat_tag = "MASTER_NORM_FLAT_MXU"; 00866 global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_MXU"; 00867 00868 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) { 00869 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MXU"; 00870 } 00871 } 00872 00873 if (lss) { 00874 00875 if (cosmics && !skyglobal) 00876 fors_extract_exit("Cosmic rays correction for LSS " 00877 "data requires --skyglobal=true"); 00878 00879 cpl_msg_info(recipe, "LSS data found"); 00880 00881 if (standard) { 00882 science_tag = "STANDARD_LSS"; 00883 reduced_science_tag = "REDUCED_STD_LSS"; 00884 unmapped_science_tag = "UNMAPPED_STD_LSS"; 00885 mapped_science_tag = "MAPPED_STD_LSS"; 00886 mapped_science_sky_tag = "MAPPED_ALL_STD_LSS"; 00887 skylines_offsets_tag = "SKY_SHIFTS_LONG_STD_LSS"; 00888 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_LSS"; 00889 disp_coeff_sky_tag = "DISP_COEFF_STD_LSS"; 00890 mapped_sky_tag = "MAPPED_SKY_STD_LSS"; 00891 unmapped_sky_tag = "UNMAPPED_SKY_STD_LSS"; 00892 object_table_tag = "OBJECT_TABLE_STD_LSS"; 00893 reduced_sky_tag = "REDUCED_SKY_STD_LSS"; 00894 reduced_error_tag = "REDUCED_ERROR_STD_LSS"; 00895 } 00896 else { 00897 science_tag = "SCIENCE_LSS"; 00898 reduced_science_tag = "REDUCED_SCI_LSS"; 00899 unmapped_science_tag = "UNMAPPED_SCI_LSS"; 00900 mapped_science_tag = "MAPPED_SCI_LSS"; 00901 mapped_science_sky_tag = "MAPPED_ALL_SCI_LSS"; 00902 skylines_offsets_tag = "SKY_SHIFTS_LONG_SCI_LSS"; 00903 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_LSS"; 00904 disp_coeff_sky_tag = "DISP_COEFF_SCI_LSS"; 00905 mapped_sky_tag = "MAPPED_SKY_SCI_LSS"; 00906 unmapped_sky_tag = "UNMAPPED_SKY_SCI_LSS"; 00907 object_table_tag = "OBJECT_TABLE_SCI_LSS"; 00908 reduced_sky_tag = "REDUCED_SKY_SCI_LSS"; 00909 reduced_error_tag = "REDUCED_ERROR_SCI_LSS"; 00910 } 00911 00912 master_norm_flat_tag = "MASTER_NORM_FLAT_LSS"; 00913 global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_LSS"; 00914 } 00915 00916 if (mos) { 00917 cpl_msg_info(recipe, "MOS data found"); 00918 if (standard) { 00919 science_tag = "STANDARD_MOS"; 00920 reduced_science_tag = "REDUCED_STD_MOS"; 00921 unmapped_science_tag = "UNMAPPED_STD_MOS"; 00922 mapped_science_tag = "MAPPED_STD_MOS"; 00923 mapped_science_sky_tag = "MAPPED_ALL_STD_MOS"; 00924 skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_MOS"; 00925 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_MOS"; 00926 disp_coeff_sky_tag = "DISP_COEFF_STD_MOS"; 00927 mapped_sky_tag = "MAPPED_SKY_STD_MOS"; 00928 unmapped_sky_tag = "UNMAPPED_SKY_STD_MOS"; 00929 object_table_tag = "OBJECT_TABLE_STD_MOS"; 00930 reduced_sky_tag = "REDUCED_SKY_STD_MOS"; 00931 reduced_error_tag = "REDUCED_ERROR_STD_MOS"; 00932 } 00933 else { 00934 science_tag = "SCIENCE_MOS"; 00935 reduced_science_tag = "REDUCED_SCI_MOS"; 00936 unmapped_science_tag = "UNMAPPED_SCI_MOS"; 00937 mapped_science_tag = "MAPPED_SCI_MOS"; 00938 mapped_science_sky_tag = "MAPPED_ALL_SCI_MOS"; 00939 skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_MOS"; 00940 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_MOS"; 00941 disp_coeff_sky_tag = "DISP_COEFF_SCI_MOS"; 00942 mapped_sky_tag = "MAPPED_SKY_SCI_MOS"; 00943 unmapped_sky_tag = "UNMAPPED_SKY_SCI_MOS"; 00944 object_table_tag = "OBJECT_TABLE_SCI_MOS"; 00945 reduced_sky_tag = "REDUCED_SKY_SCI_MOS"; 00946 reduced_error_tag = "REDUCED_ERROR_SCI_MOS"; 00947 } 00948 00949 master_norm_flat_tag = "MASTER_NORM_FLAT_MOS"; 00950 global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_MOS"; 00951 00952 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) { 00953 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_MOS"; 00954 } 00955 } 00956 00957 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) 00958 fors_extract_exit("Missing required input: MASTER_BIAS"); 00959 00960 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 00961 fors_extract_exit("Too many in input: MASTER_BIAS"); 00962 00963 if (skyalign >= 0) 00964 if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1) 00965 fors_extract_exit("Too many in input: MASTER_SKYLINECAT"); 00966 00967 if (cpl_frameset_count_tags(frameset, global_distortion_tag) == 0) 00968 fors_extract_exit("Missing required input: MASTER_DISTORTION_TABLE"); 00969 00970 if (cpl_frameset_count_tags(frameset, global_distortion_tag) > 1) 00971 fors_extract_exit("Too many in input: MASTER_DISTORTION_TABLE"); 00972 00973 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) { 00974 if (flatfield) { 00975 cpl_msg_error(recipe, "Too many in input: %s", 00976 master_norm_flat_tag); 00977 fors_extract_exit(NULL); 00978 } 00979 else { 00980 cpl_msg_warning(recipe, "%s in input are ignored, " 00981 "since flat field correction was not requested", 00982 master_norm_flat_tag); 00983 } 00984 } 00985 00986 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) { 00987 if (!flatfield) { 00988 cpl_msg_warning(recipe, "%s in input is ignored, " 00989 "since flat field correction was not requested", 00990 master_norm_flat_tag); 00991 } 00992 } 00993 00994 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) { 00995 if (flatfield) { 00996 cpl_msg_error(recipe, "Flat field correction was requested, " 00997 "but no %s are found in input", 00998 master_norm_flat_tag); 00999 fors_extract_exit(NULL); 01000 } 01001 } 01002 01003 cpl_msg_indent_less(); 01004 01005 01006 /* 01007 * Loading input data 01008 */ 01009 01010 exptime = cpl_calloc(nscience, sizeof(double)); 01011 01012 if (nscience > 1) { 01013 01014 cpl_msg_info(recipe, "Load %d scientific frames and median them...", 01015 nscience); 01016 cpl_msg_indent_more(); 01017 01018 all_science = cpl_imagelist_new(); 01019 01020 header = dfs_load_header(frameset, science_tag, 0); 01021 01022 if (header == NULL) 01023 fors_extract_exit("Cannot load scientific frame header"); 01024 01025 alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME"); 01026 01027 if (cpl_error_get_code() != CPL_ERROR_NONE) 01028 fors_extract_exit("Missing keyword EXPTIME in scientific " 01029 "frame header"); 01030 01031 cpl_propertylist_delete(header); header = NULL; 01032 01033 cpl_msg_info(recipe, "Scientific frame 1 exposure time: %.2f s", 01034 exptime[0]); 01035 01036 for (i = 1; i < nscience; i++) { 01037 01038 header = dfs_load_header(frameset, NULL, 0); 01039 01040 if (header == NULL) 01041 fors_extract_exit("Cannot load scientific frame header"); 01042 01043 exptime[i] = cpl_propertylist_get_double(header, "EXPTIME"); 01044 01045 alltime += exptime[i]; 01046 01047 if (cpl_error_get_code() != CPL_ERROR_NONE) 01048 fors_extract_exit("Missing keyword EXPTIME in scientific " 01049 "frame header"); 01050 01051 cpl_propertylist_delete(header); header = NULL; 01052 01053 cpl_msg_info(recipe, "Scientific frame %d exposure time: %.2f s", 01054 i+1, exptime[i]); 01055 } 01056 01057 spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0); 01058 01059 if (spectra == NULL) 01060 fors_extract_exit("Cannot load scientific frame"); 01061 01062 cpl_image_divide_scalar(spectra, exptime[0]); 01063 cpl_imagelist_set(all_science, spectra, 0); spectra = NULL; 01064 01065 for (i = 1; i < nscience; i++) { 01066 01067 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01068 01069 if (spectra) { 01070 cpl_image_divide_scalar(spectra, exptime[i]); 01071 cpl_imagelist_set(all_science, spectra, i); spectra = NULL; 01072 } 01073 else 01074 fors_extract_exit("Cannot load scientific frame"); 01075 01076 } 01077 01078 spectra = cpl_imagelist_collapse_median_create(all_science); 01079 cpl_image_multiply_scalar(spectra, alltime); 01080 01081 cpl_imagelist_delete(all_science); 01082 } 01083 else { 01084 cpl_msg_info(recipe, "Load scientific exposure..."); 01085 cpl_msg_indent_more(); 01086 01087 header = dfs_load_header(frameset, science_tag, 0); 01088 01089 if (header == NULL) 01090 fors_extract_exit("Cannot load scientific frame header"); 01091 01092 01093 /* 01094 * Insert here a check on supported filters: 01095 */ 01096 01097 wheel4 = (char *)cpl_propertylist_get_string(header, 01098 "ESO INS OPTI9 TYPE"); 01099 if (cpl_error_get_code() != CPL_ERROR_NONE) { 01100 fors_extract_exit("Missing ESO INS OPTI9 TYPE in flat header"); 01101 } 01102 01103 if (strcmp("FILT", wheel4) == 0) { 01104 wheel4 = (char *)cpl_propertylist_get_string(header, 01105 "ESO INS OPTI9 NAME"); 01106 cpl_msg_error(recipe, "Unsupported filter: %s", wheel4); 01107 fors_extract_exit(NULL); 01108 } 01109 01110 01111 alltime = exptime[0] = cpl_propertylist_get_double(header, "EXPTIME"); 01112 01113 if (cpl_error_get_code() != CPL_ERROR_NONE) 01114 fors_extract_exit("Missing keyword EXPTIME in scientific " 01115 "frame header"); 01116 01117 cpl_propertylist_delete(header); header = NULL; 01118 01119 cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 01120 exptime[0]); 01121 01122 spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0); 01123 } 01124 01125 if (spectra == NULL) 01126 fors_extract_exit("Cannot load scientific frame"); 01127 01128 cpl_free(exptime); exptime = NULL; 01129 01130 cpl_msg_indent_less(); 01131 01132 01133 /* 01134 * Get the reference wavelength and the rebin factor along the 01135 * dispersion direction from a scientific exposure 01136 */ 01137 01138 header = dfs_load_header(frameset, science_tag, 0); 01139 01140 if (header == NULL) 01141 fors_extract_exit("Cannot load scientific frame header"); 01142 01143 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 01144 if (instrume == NULL) 01145 fors_extract_exit("Missing keyword INSTRUME in sientific header"); 01146 instrume = cpl_strdup(instrume); 01147 01148 if (instrume[4] == '1') 01149 snprintf(version, 80, "%s/%s", "fors1", VERSION); 01150 if (instrume[4] == '2') 01151 snprintf(version, 80, "%s/%s", "fors2", VERSION); 01152 01153 cpl_free(instrume); instrume = NULL; 01154 01155 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 01156 01157 if (cpl_error_get_code() != CPL_ERROR_NONE) 01158 fors_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific " 01159 "frame header"); 01160 01161 if (reference < 3000.0) /* Perhaps in nanometers... */ 01162 reference *= 10; 01163 01164 if (reference < 3000.0 || reference > 13000.0) { 01165 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 01166 "keyword ESO INS GRIS1 WLEN in scientific frame header", 01167 reference); 01168 fors_extract_exit(NULL); 01169 } 01170 01171 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 01172 01173 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 01174 01175 if (cpl_error_get_code() != CPL_ERROR_NONE) 01176 fors_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific " 01177 "frame header"); 01178 01179 if (rebin != 1) { 01180 dispersion *= rebin; 01181 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01182 "resampling step used is %f A/pixel", rebin, 01183 dispersion); 01184 } 01185 01186 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01187 01188 if (cpl_error_get_code() != CPL_ERROR_NONE) 01189 fors_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific " 01190 "frame header"); 01191 01192 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 01193 01194 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON"); 01195 01196 if (cpl_error_get_code() != CPL_ERROR_NONE) 01197 fors_extract_exit("Missing keyword ESO DET OUT1 RON in scientific " 01198 "frame header"); 01199 01200 ron /= gain; /* Convert from electrons to ADU */ 01201 01202 cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron); 01203 01204 coll = (char *)cpl_propertylist_get_string(header, "ESO INS COLL NAME"); 01205 01206 if (cpl_error_get_code() != CPL_ERROR_NONE) 01207 fors_extract_exit("Missing keyword ESO INS COLL NAME in scientific " 01208 "frame header"); 01209 01210 cpl_msg_info(recipe, "The collimator is : %s", coll); 01211 01212 if (strcmp(coll, "COLL_HR") == 0) 01213 fors_extract_exit("HR collimator is not yet supported by this recipe"); 01214 01215 01216 if (mos) 01217 { 01218 int nslits_out_det; 01219 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det); 01220 } 01221 else if (lss) 01222 maskslits = mos_load_slits_fors_lss(header); 01223 else 01224 maskslits = mos_load_slits_fors_mxu(header); 01225 01226 if (lss) { 01227 if (skylocal) { 01228 if (cosmics) 01229 fors_extract_exit("Cosmic rays correction for LSS " 01230 "data requires --skyglobal=true"); 01231 skymedian = skylocal; 01232 skylocal = 0; 01233 } 01234 } 01235 01236 global = dfs_load_table(frameset, global_distortion_tag, 1); 01237 if (global == NULL) 01238 fors_extract_exit("Cannot load global distortion table"); 01239 01240 /* Leave the header on for the next step... */ 01241 01242 01243 /* 01244 * Remove the master bias 01245 */ 01246 01247 cpl_msg_info(recipe, "Remove the master bias..."); 01248 01249 bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1); 01250 01251 if (bias == NULL) 01252 fors_extract_exit("Cannot load master bias"); 01253 01254 overscans = mos_load_overscans_vimos(header, 1); 01255 cpl_propertylist_delete(header); header = NULL; 01256 dummy = mos_remove_bias(spectra, bias, overscans); 01257 cpl_image_delete(spectra); spectra = dummy; dummy = NULL; 01258 cpl_image_delete(bias); bias = NULL; 01259 cpl_table_delete(overscans); overscans = NULL; 01260 01261 if (spectra == NULL) 01262 fors_extract_exit("Cannot remove bias from scientific frame"); 01263 01264 nx = cpl_image_get_size_x(spectra); 01265 ny = cpl_image_get_size_y(spectra); 01266 01267 if (ny == 400 && nx == 2048) 01268 narrow = 1; 01269 01270 if (narrow) { 01271 ny = 2048; 01272 dummy = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01273 cpl_image_copy(dummy, spectra, 1, 825); /* (2048 - 400)/2 + 1 */ 01274 if (cpl_error_get_code()) 01275 fors_extract_exit("Problems expanding scientific image"); 01276 cpl_image_delete(spectra); spectra = dummy; dummy = NULL; 01277 } 01278 01279 cpl_msg_indent_less(); 01280 cpl_msg_info(recipe, "Load normalised flat field (if present)..."); 01281 cpl_msg_indent_more(); 01282 01283 if (flatfield) { 01284 01285 norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 01286 CPL_TYPE_FLOAT, 0, 1); 01287 01288 if (norm_flat) { 01289 if (narrow) { 01290 dummy = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01291 cpl_image_copy(dummy, norm_flat, 1, 825); 01292 if (cpl_error_get_code()) 01293 fors_extract_exit("Problems expanding flat image"); 01294 cpl_image_delete(norm_flat); norm_flat = dummy; dummy = NULL; 01295 } 01296 cpl_msg_info(recipe, "Apply flat field correction..."); 01297 if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) { 01298 cpl_msg_error(recipe, "Failure of flat field correction: %s", 01299 cpl_error_get_message()); 01300 fors_extract_exit(NULL); 01301 } 01302 cpl_image_delete(norm_flat); norm_flat = NULL; 01303 } 01304 else { 01305 cpl_msg_error(recipe, "Cannot load input %s for flat field " 01306 "correction", master_norm_flat_tag); 01307 fors_extract_exit(NULL); 01308 } 01309 01310 } 01311 01312 01313 if (skyalign >= 0) { 01314 cpl_msg_indent_less(); 01315 cpl_msg_info(recipe, "Load input sky line catalog..."); 01316 cpl_msg_indent_more(); 01317 01318 wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1); 01319 01320 if (wavelengths) { 01321 01322 /* 01323 * Cast the wavelengths into a (double precision) CPL vector 01324 */ 01325 01326 nlines = cpl_table_get_nrow(wavelengths); 01327 01328 if (nlines == 0) 01329 fors_extract_exit("Empty input sky line catalog"); 01330 01331 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 01332 cpl_msg_error(recipe, "Missing column %s in input line " 01333 "catalog table", wcolumn); 01334 fors_extract_exit(NULL); 01335 } 01336 01337 line = cpl_malloc(nlines * sizeof(double)); 01338 01339 for (i = 0; i < nlines; i++) 01340 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 01341 01342 cpl_table_delete(wavelengths); wavelengths = NULL; 01343 01344 lines = cpl_vector_wrap(nlines, line); 01345 } 01346 else { 01347 cpl_msg_info(recipe, "No sky line catalog found in input - fine!"); 01348 } 01349 } 01350 01351 01352 /* 01353 * Load the slit location table, or provide a dummy one in case 01354 * of LSS data (single slit spanning whole image) 01355 */ 01356 01357 slits = mos_build_slit_location(global, maskslits, ny); 01358 if (slits == NULL) 01359 fors_extract_exit("Cannot create slits location table"); 01360 01361 01362 /* 01363 * Load the spectral curvature table in case of MOS or MXU data 01364 */ 01365 01366 polytraces = mos_build_curv_coeff(global, maskslits, slits); 01367 if (polytraces == NULL) 01368 fors_extract_exit("Cannot create spectral curvature table"); 01369 01370 cpl_table_delete(maskslits); maskslits = NULL; 01371 01372 cpl_msg_indent_less(); 01373 cpl_msg_info(recipe, "Processing scientific spectra..."); 01374 cpl_msg_indent_more(); 01375 01376 /* 01377 * This one will also generate the spatial map from the spectral 01378 * curvature table (in the case of multislit data) 01379 */ 01380 01381 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01382 01383 smapped = mos_spatial_calibration(spectra, slits, polytraces, reference, 01384 startwavelength, endwavelength, 01385 dispersion, flux, coordinate); 01386 01387 01388 /* 01389 * Load the wavelength calibration table 01390 */ 01391 01392 idscoeff = mos_build_disp_coeff(global, slits); 01393 if (idscoeff == NULL) 01394 fors_extract_exit("Cannot create wavelength calibration table"); 01395 01396 cpl_table_delete(global); global = NULL; 01397 01398 01399 /* 01400 * Generate a rectified wavelength map from the wavelength calibration 01401 * table 01402 */ 01403 01404 rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 01405 endwavelength); 01406 01407 if (dispersion > 1.0) 01408 highres = 0; 01409 else 01410 highres = 1; 01411 01412 if (skyalign >= 0) { 01413 if (skyalign) { 01414 cpl_msg_info(recipe, "Align wavelength solution to reference " 01415 "skylines applying %d order residual fit...", skyalign); 01416 } 01417 else { 01418 cpl_msg_info(recipe, "Align wavelength solution to reference " 01419 "skylines applying median offset..."); 01420 } 01421 01422 if (lss) { 01423 offsets = mos_wavelength_align_lss(smapped, reference, 01424 startwavelength, endwavelength, 01425 idscoeff, lines, highres, 01426 skyalign, rainbow, 4); 01427 } 01428 else { 01429 offsets = mos_wavelength_align(smapped, slits, reference, 01430 startwavelength, endwavelength, 01431 idscoeff, lines, highres, skyalign, 01432 rainbow, 4); 01433 } 01434 01435 cpl_vector_delete(lines); lines = NULL; 01436 01437 if (offsets) { 01438 if (standard) 01439 cpl_msg_warning(recipe, "Alignment of the wavelength solution " 01440 "to reference sky lines may be unreliable in " 01441 "this case!"); 01442 01443 if (dfs_save_table(frameset, offsets, skylines_offsets_tag, NULL, 01444 parlist, recipe, version)) 01445 fors_extract_exit(NULL); 01446 01447 cpl_table_delete(offsets); offsets = NULL; 01448 } 01449 else { 01450 cpl_msg_warning(recipe, "Alignment of the wavelength solution " 01451 "to reference sky lines could not be done!"); 01452 skyalign = -1; 01453 } 01454 01455 } 01456 01457 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 01458 polytraces, reference, 01459 startwavelength, endwavelength, 01460 dispersion); 01461 01462 cpl_image_delete(rainbow); rainbow = NULL; 01463 cpl_image_delete(coordinate); coordinate = NULL; 01464 01465 /* 01466 * Here the wavelength calibrated slit spectra are created. This frame 01467 * contains sky_science. 01468 */ 01469 01470 mapped_sky = mos_wavelength_calibration(smapped, reference, 01471 startwavelength, endwavelength, 01472 dispersion, idscoeff, flux); 01473 01474 cpl_msg_indent_less(); 01475 cpl_msg_info(recipe, "Check applied wavelength against skylines..."); 01476 cpl_msg_indent_more(); 01477 01478 mean_rms = mos_distortions_rms(mapped_sky, NULL, startwavelength, 01479 dispersion, 6, highres); 01480 01481 cpl_msg_info(recipe, "Mean residual: %f", mean_rms); 01482 01483 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01484 01485 header = cpl_propertylist_new(); 01486 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01487 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01488 cpl_propertylist_update_double(header, "CRVAL1", 01489 startwavelength + dispersion/2); 01490 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01491 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01492 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01493 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01494 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01495 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01496 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01497 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01498 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01499 01500 if (time_normalise) { 01501 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime); 01502 if (dfs_save_image(frameset, dummy, mapped_science_sky_tag, header, 01503 parlist, recipe, version)) 01504 fors_extract_exit(NULL); 01505 cpl_image_delete(dummy); dummy = NULL; 01506 } 01507 else { 01508 if (dfs_save_image(frameset, mapped_sky, mapped_science_sky_tag, 01509 header, parlist, recipe, version)) 01510 fors_extract_exit(NULL); 01511 } 01512 01513 /* if (skyglobal == 0 && skymedian < 0) { NSS */ 01514 if (skyglobal == 0 && skymedian == 0 && skylocal == 0) { 01515 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01516 } 01517 01518 if (skyglobal || skylocal) { 01519 01520 cpl_msg_indent_less(); 01521 01522 if (skyglobal) { 01523 cpl_msg_info(recipe, "Global sky determination..."); 01524 cpl_msg_indent_more(); 01525 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01526 sky = mos_sky_map_super(spectra, wavemap, dispersion, 01527 2.0, 50, skymap); 01528 if (sky) 01529 cpl_image_subtract(spectra, skymap); 01530 else 01531 cpl_image_delete(skymap); skymap = NULL; 01532 } 01533 else { 01534 cpl_msg_info(recipe, "Local sky determination..."); 01535 cpl_msg_indent_more(); 01536 skymap = mos_subtract_sky(spectra, slits, polytraces, reference, 01537 startwavelength, endwavelength, dispersion); 01538 } 01539 01540 if (skymap) { 01541 if (skyglobal) { 01542 if (time_normalise) 01543 cpl_table_divide_scalar(sky, "sky", alltime); 01544 if (dfs_save_table(frameset, sky, global_sky_spectrum_tag, 01545 NULL, parlist, recipe, version)) 01546 fors_extract_exit(NULL); 01547 01548 cpl_table_delete(sky); sky = NULL; 01549 } 01550 01551 save_header = dfs_load_header(frameset, science_tag, 0); 01552 01553 if (time_normalise) 01554 cpl_image_divide_scalar(skymap, alltime); 01555 if (dfs_save_image(frameset, skymap, unmapped_sky_tag, 01556 save_header, parlist, recipe, version)) 01557 fors_extract_exit(NULL); 01558 01559 cpl_image_delete(skymap); skymap = NULL; 01560 01561 if (dfs_save_image(frameset, spectra, unmapped_science_tag, 01562 save_header, parlist, recipe, version)) 01563 fors_extract_exit(NULL); 01564 01565 cpl_propertylist_delete(save_header); save_header = NULL; 01566 01567 if (cosmics) { 01568 cpl_msg_info(recipe, "Removing cosmic rays..."); 01569 mos_clean_cosmics(spectra, gain, -1., -1.); 01570 } 01571 01572 /* 01573 * The spatially rectified image, that contained the sky, 01574 * is replaced by a sky-subtracted spatially rectified image: 01575 */ 01576 01577 cpl_image_delete(smapped); smapped = NULL; 01578 01579 if (lss) { 01580 smapped = cpl_image_duplicate(spectra); 01581 } 01582 else { 01583 smapped = mos_spatial_calibration(spectra, slits, polytraces, 01584 reference, startwavelength, 01585 endwavelength, dispersion, 01586 flux, NULL); 01587 } 01588 } 01589 else { 01590 cpl_msg_warning(recipe, "Sky subtraction failure"); 01591 if (cosmics) 01592 cpl_msg_warning(recipe, "Cosmic rays removal not performed!"); 01593 cosmics = skylocal = skyglobal = 0; 01594 } 01595 } 01596 01597 cpl_image_delete(spectra); spectra = NULL; 01598 cpl_table_delete(polytraces); polytraces = NULL; 01599 01600 if (skyalign >= 0) { 01601 save_header = dfs_load_header(frameset, science_tag, 0); 01602 if (dfs_save_image(frameset, wavemap, wavelength_map_sky_tag, 01603 save_header, parlist, recipe, version)) 01604 fors_extract_exit(NULL); 01605 cpl_propertylist_delete(save_header); save_header = NULL; 01606 } 01607 01608 cpl_image_delete(wavemap); wavemap = NULL; 01609 01610 mapped = mos_wavelength_calibration(smapped, reference, 01611 startwavelength, endwavelength, 01612 dispersion, idscoeff, flux); 01613 01614 cpl_image_delete(smapped); smapped = NULL; 01615 01616 /* if (skymedian >= 0) { NSS */ 01617 if (skymedian) { 01618 cpl_msg_indent_less(); 01619 cpl_msg_info(recipe, "Local sky determination..."); 01620 cpl_msg_indent_more(); 01621 01622 /* NSS skylocalmap = mos_sky_local(mapped, slits, skymedian); */ 01623 /* skylocalmap = mos_sky_local(mapped, slits, 0); */ 01624 skylocalmap = mos_sky_local_old(mapped, slits); 01625 cpl_image_subtract(mapped, skylocalmap); 01626 /* 01627 if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 01628 parlist, recipe, version)) 01629 fors_extract_exit(NULL); 01630 */ 01631 cpl_image_delete(skylocalmap); skylocalmap = NULL; 01632 } 01633 01634 /* if (skyglobal || skymedian >= 0 || skylocal) { NSS */ 01635 if (skyglobal || skymedian || skylocal) { 01636 01637 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped); 01638 01639 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01640 01641 if (time_normalise) { 01642 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime); 01643 if (dfs_save_image(frameset, dummy, mapped_sky_tag, header, 01644 parlist, recipe, version)) 01645 fors_extract_exit(NULL); 01646 cpl_image_delete(dummy); dummy = NULL; 01647 } 01648 else { 01649 if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 01650 parlist, recipe, version)) 01651 fors_extract_exit(NULL); 01652 } 01653 01654 cpl_msg_indent_less(); 01655 cpl_msg_info(recipe, "Object detection..."); 01656 cpl_msg_indent_more(); 01657 01658 if (cosmics || nscience > 1) { 01659 dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius, 01660 cont_radius); 01661 } 01662 else { 01663 mapped_cleaned = cpl_image_duplicate(mapped); 01664 mos_clean_cosmics(mapped_cleaned, gain, -1., -1.); 01665 dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 01666 ext_radius, cont_radius); 01667 01668 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL; 01669 } 01670 01671 cpl_image_delete(dummy); dummy = NULL; 01672 01673 if (dfs_save_table(frameset, slits, object_table_tag, NULL, parlist, 01674 recipe, version)) 01675 fors_extract_exit(NULL); 01676 01677 cpl_msg_indent_less(); 01678 cpl_msg_info(recipe, "Object extraction..."); 01679 cpl_msg_indent_more(); 01680 01681 images = mos_extract_objects(mapped, skylocalmap, slits, 01682 ext_mode, ron, gain, 1); 01683 01684 cpl_image_delete(skylocalmap); skylocalmap = NULL; 01685 01686 if (images) { 01687 if (time_normalise) 01688 cpl_image_divide_scalar(images[0], alltime); 01689 if (dfs_save_image(frameset, images[0], reduced_science_tag, header, 01690 parlist, recipe, version)) 01691 fors_extract_exit(NULL); 01692 cpl_image_delete(images[0]); 01693 01694 if (time_normalise) 01695 cpl_image_divide_scalar(images[1], alltime); 01696 if (dfs_save_image(frameset, images[1], reduced_sky_tag, header, 01697 parlist, recipe, version)) 01698 fors_extract_exit(NULL); 01699 cpl_image_delete(images[1]); 01700 01701 if (time_normalise) 01702 cpl_image_divide_scalar(images[2], alltime); 01703 if (dfs_save_image(frameset, images[2], reduced_error_tag, header, 01704 parlist, recipe, version)) 01705 fors_extract_exit(NULL); 01706 cpl_image_delete(images[2]); 01707 01708 cpl_free(images); 01709 } 01710 else { 01711 cpl_msg_warning(recipe, "No objects found: the products " 01712 "%s, %s, and %s are not created", 01713 reduced_science_tag, reduced_sky_tag, 01714 reduced_error_tag); 01715 } 01716 01717 } 01718 01719 cpl_table_delete(slits); slits = NULL; 01720 01721 if (skyalign >= 0) { 01722 if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag, NULL, 01723 parlist, recipe, version)) 01724 fors_extract_exit(NULL); 01725 } 01726 01727 cpl_table_delete(idscoeff); idscoeff = NULL; 01728 01729 /* if (skyglobal || skymedian >= 0) { NSS */ 01730 if (skyglobal || skymedian || skylocal) { 01731 if (time_normalise) 01732 cpl_image_divide_scalar(mapped, alltime); 01733 if (dfs_save_image(frameset, mapped, mapped_science_tag, header, 01734 parlist, recipe, version)) 01735 fors_extract_exit(NULL); 01736 } 01737 01738 cpl_image_delete(mapped); mapped = NULL; 01739 cpl_propertylist_delete(header); header = NULL; 01740 01741 if (cpl_error_get_code()) { 01742 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 01743 fors_extract_exit(NULL); 01744 } 01745 01746 return 0; 01747 }