FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_pmos_extract.c,v 1.7 2013/02/28 15:15: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:15:25 $ 00024 * $Revision: 1.7 $ 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 <assert.h> 00036 00037 #include <cpl.h> 00038 #include <moses.h> 00039 #include <fors_dfs.h> 00040 #include <fors_utils.h> 00041 #include <fors_qc.h> 00042 00043 static int fors_pmos_extract_create(cpl_plugin *); 00044 static int fors_pmos_extract_exec(cpl_plugin *); 00045 static int fors_pmos_extract_destroy(cpl_plugin *); 00046 static int fors_pmos_extract(cpl_parameterlist *, cpl_frameset *); 00047 00048 static float * fors_check_angles(cpl_frameset *, int, const char *, int *); 00049 static int 00050 fors_find_angle_pos(float * angles, int nangles, float angle); 00051 00052 static char fors_pmos_extract_description[] = 00053 "This recipe is used to reduce scientific spectra using the extraction\n" 00054 "mask and the products created by the recipe fors_mpol_calib. The spectra\n" 00055 "are bias subtracted, flat fielded (if a normalised flat field is specified)\n" 00056 "and remapped eliminating the optical distortions. The wavelength calibration\n" 00057 "can be optionally upgraded using a number of sky lines: if no sky lines\n" 00058 "catalog of wavelengths is specified, an internal one is used instead.\n" 00059 "If the alignment to the sky lines is performed, the input dispersion\n" 00060 "coefficients table is upgraded and saved to disk, and a new CCD wavelengths\n" 00061 "map is created.\n" 00062 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n" 00063 "depending on the instrument mode, and in particular on the grism used)\n" 00064 "may also be specified: this table contains a default recipe parameter\n" 00065 "setting to control the way spectra are extracted for a specific instrument\n" 00066 "mode, as it is used for automatic run of the pipeline on Paranal and in\n" 00067 "Garching. If this table is specified, it will modify the default recipe\n" 00068 "parameter setting, with the exception of those parameters which have been\n" 00069 "explicitly modifyed on the command line. If a grism table is not specified,\n" 00070 "the input recipe parameters values will always be read from the command\n" 00071 "line, or from an esorex configuration file if present, or from their\n" 00072 "generic default values (that are rarely meaningful).\n" 00073 "Either a scientific or a standard star exposure can be specified in input.\n" 00074 "The acronym SCI on products should be read STD in case of standard stars\n" 00075 "observations.\n\n" 00076 "Input files:\n\n" 00077 " DO category: Type: Explanation: Required:\n" 00078 " SCIENCE_PMOS Raw Scientific exposure Y\n" 00079 " or STANDARD_PMOS Raw Standard star exposure Y\n" 00080 " MASTER_BIAS Calib Master bias Y\n" 00081 " GRISM_TABLE Calib Grism table .\n" 00082 " MASTER_SKYLINECAT Calib Sky lines catalog .\n" 00083 "\n" 00084 " MASTER_NORM_FLAT_PMOS Calib Normalised flat field .\n" 00085 " DISP_COEFF_PMOS Calib Inverse dispersion Y\n" 00086 " CURV_COEFF_PMOS Calib Spectral curvature Y\n" 00087 " SLIT_LOCATION_PMOS Calib Slits positions table Y\n" 00088 " RETARDER_WAVEPLATE_CHROMATISM Calib Chromatism correction .\n" 00089 "\n" 00090 "Output files:\n\n" 00091 " DO category: Data type: Explanation:\n" 00092 " REDUCED_SCI_PMOS FITS image Extracted scientific spectra\n" 00093 " REDUCED_SKY_SCI_PMOS FITS image Extracted sky spectra\n" 00094 " REDUCED_ERROR_SCI_PMOS FITS image Errors on extracted spectra\n" 00095 " REDUCED_SCI_X_PMOS FITS image X Stokes parameter (and L)\n" 00096 " REDUCED_ERROR_X_PMOS FITS image Error on X Stokes parameter\n" 00097 " REDUCED_NUL_X_PMOS FITS image Null parameter for X\n" 00098 " REDUCED_POL_ANGLE_PMOS FITS image Direction of linear polarization\n" 00099 " REDUCED_POL_ANGLE_ERROR_PMOS FITS image Error on polarization direction\n" 00100 " UNMAPPED_SCI_PMOS FITS image Sky subtracted scientific spectra\n" 00101 " MAPPED_SCI_PMOS FITS image Rectified scientific spectra\n" 00102 " MAPPED_ALL_SCI_PMOS FITS image Rectified science spectra with sky\n" 00103 " MAPPED_SKY_SCI_PMOS FITS image Rectified sky spectra\n" 00104 " UNMAPPED_SKY_SCI_PMOS FITS image Sky on CCD\n" 00105 " GLOBAL_SKY_SPECTRUM_PMOS FITS table Global sky spectrum\n" 00106 " OBJECT_TABLE_SCI_PMOS FITS table Positions of detected objects\n" 00107 " OBJECT_TABLE_POL_SCI_PMOS FITS table Positions of real objects\n" 00108 "\n" 00109 " Only if the sky-alignment of the wavelength solution is requested:\n" 00110 " DISP_COEFF_SCI_PMOS FITS table Upgraded dispersion coefficients\n" 00111 " WAVELENGTH_MAP_SCI_PMOS FITS image Upgraded wavelength map\n\n"; 00112 00113 #define fors_pmos_extract_exit(message) \ 00114 { \ 00115 if (message) cpl_msg_error(recipe, message); \ 00116 cpl_free(instrume); \ 00117 cpl_image_delete(dummy); \ 00118 cpl_image_delete(mapped_sky); \ 00119 cpl_image_delete(mapped_cleaned); \ 00120 cpl_image_delete(skymap); \ 00121 cpl_image_delete(smapped); \ 00122 cpl_table_delete(offsets); \ 00123 cpl_table_delete(sky); \ 00124 cpl_image_delete(bias); \ 00125 cpl_image_delete(spectra); \ 00126 cpl_image_delete(coordinate); \ 00127 cpl_image_delete(norm_flat); \ 00128 cpl_image_delete(rainbow); \ 00129 cpl_image_delete(rectified); \ 00130 cpl_image_delete(wavemap); \ 00131 cpl_propertylist_delete(header); \ 00132 cpl_propertylist_delete(save_header); \ 00133 cpl_table_delete(grism_table); \ 00134 cpl_table_delete(idscoeff); \ 00135 cpl_table_delete(maskslits); \ 00136 cpl_table_delete(overscans); \ 00137 cpl_table_delete(polytraces); \ 00138 cpl_table_delete(wavelengths); \ 00139 cpl_vector_delete(lines); \ 00140 cpl_msg_indent_less(); \ 00141 return -1; \ 00142 } 00143 00144 00145 #define fors_pmos_extract_exit_memcheck(message) \ 00146 { \ 00147 if (message) cpl_msg_info(recipe, message); \ 00148 cpl_free(instrume); \ 00149 cpl_image_delete(dummy); \ 00150 cpl_image_delete(mapped_cleaned); \ 00151 cpl_image_delete(mapped_sky); \ 00152 cpl_image_delete(skymap); \ 00153 cpl_image_delete(smapped); \ 00154 cpl_table_delete(offsets); \ 00155 cpl_table_delete(sky); \ 00156 cpl_image_delete(bias); \ 00157 cpl_image_delete(spectra); \ 00158 cpl_image_delete(coordinate); \ 00159 cpl_image_delete(norm_flat); \ 00160 cpl_image_delete(rainbow); \ 00161 cpl_image_delete(rectified); \ 00162 cpl_image_delete(wavemap); \ 00163 cpl_propertylist_delete(header); \ 00164 cpl_propertylist_delete(save_header); \ 00165 cpl_table_delete(grism_table); \ 00166 cpl_table_delete(idscoeff); \ 00167 cpl_table_delete(maskslits); \ 00168 cpl_table_delete(overscans); \ 00169 cpl_table_delete(polytraces); \ 00170 cpl_table_delete(wavelengths); \ 00171 cpl_vector_delete(lines); \ 00172 cpl_msg_indent_less(); \ 00173 return 0; \ 00174 } 00175 00176 00188 int cpl_plugin_get_info(cpl_pluginlist *list) 00189 { 00190 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00191 cpl_plugin *plugin = &recipe->interface; 00192 00193 cpl_plugin_init(plugin, 00194 CPL_PLUGIN_API, 00195 FORS_BINARY_VERSION, 00196 CPL_PLUGIN_TYPE_RECIPE, 00197 "fors_pmos_extract", 00198 "Extraction of scientific spectra", 00199 fors_pmos_extract_description, 00200 "Carlo Izzo", 00201 PACKAGE_BUGREPORT, 00202 "This file is currently part of the FORS Instrument Pipeline\n" 00203 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00204 "This program is free software; you can redistribute it and/or modify\n" 00205 "it under the terms of the GNU General Public License as published by\n" 00206 "the Free Software Foundation; either version 2 of the License, or\n" 00207 "(at your option) any later version.\n\n" 00208 "This program is distributed in the hope that it will be useful,\n" 00209 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00210 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00211 "GNU General Public License for more details.\n\n" 00212 "You should have received a copy of the GNU General Public License\n" 00213 "along with this program; if not, write to the Free Software Foundation,\n" 00214 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00215 fors_pmos_extract_create, 00216 fors_pmos_extract_exec, 00217 fors_pmos_extract_destroy); 00218 00219 cpl_pluginlist_append(list, plugin); 00220 00221 return 0; 00222 } 00223 00224 00235 static int fors_pmos_extract_create(cpl_plugin *plugin) 00236 { 00237 cpl_recipe *recipe; 00238 cpl_parameter *p; 00239 00240 00241 /* 00242 * Check that the plugin is part of a valid recipe 00243 */ 00244 00245 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00246 recipe = (cpl_recipe *)plugin; 00247 else 00248 return -1; 00249 00250 /* 00251 * Create the parameters list in the cpl_recipe object 00252 */ 00253 00254 recipe->parameters = cpl_parameterlist_new(); 00255 00256 00257 /* 00258 * Dispersion 00259 */ 00260 00261 p = cpl_parameter_new_value("fors.fors_pmos_extract.dispersion", 00262 CPL_TYPE_DOUBLE, 00263 "Resampling step (Angstrom/pixel)", 00264 "fors.fors_pmos_extract", 00265 0.0); 00266 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00267 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00268 cpl_parameterlist_append(recipe->parameters, p); 00269 00270 /* 00271 * Sky lines alignment 00272 */ 00273 00274 p = cpl_parameter_new_value("fors.fors_pmos_extract.skyalign", 00275 CPL_TYPE_INT, 00276 "Polynomial order for sky lines alignment, " 00277 "or -1 to avoid alignment", 00278 "fors.fors_pmos_extract", 00279 0); 00280 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign"); 00281 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00282 cpl_parameterlist_append(recipe->parameters, p); 00283 00284 /* 00285 * Line catalog table column containing the sky reference wavelengths 00286 */ 00287 00288 p = cpl_parameter_new_value("fors.fors_pmos_extract.wcolumn", 00289 CPL_TYPE_STRING, 00290 "Name of sky line catalog table column " 00291 "with wavelengths", 00292 "fors.fors_pmos_extract", 00293 "WLEN"); 00294 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn"); 00295 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00296 cpl_parameterlist_append(recipe->parameters, p); 00297 00298 /* 00299 * Start wavelength for spectral extraction 00300 */ 00301 00302 p = cpl_parameter_new_value("fors.fors_pmos_extract.startwavelength", 00303 CPL_TYPE_DOUBLE, 00304 "Start wavelength in spectral extraction", 00305 "fors.fors_pmos_extract", 00306 0.0); 00307 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00308 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00309 cpl_parameterlist_append(recipe->parameters, p); 00310 00311 /* 00312 * End wavelength for spectral extraction 00313 */ 00314 00315 p = cpl_parameter_new_value("fors.fors_pmos_extract.endwavelength", 00316 CPL_TYPE_DOUBLE, 00317 "End wavelength in spectral extraction", 00318 "fors.fors_pmos_extract", 00319 0.0); 00320 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00321 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00322 cpl_parameterlist_append(recipe->parameters, p); 00323 00324 /* 00325 * Flux conservation 00326 */ 00327 00328 p = cpl_parameter_new_value("fors.fors_pmos_extract.flux", 00329 CPL_TYPE_BOOL, 00330 "Apply flux conservation", 00331 "fors.fors_pmos_extract", 00332 TRUE); 00333 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux"); 00334 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00335 cpl_parameterlist_append(recipe->parameters, p); 00336 00337 /* 00338 * Apply flat field 00339 */ 00340 00341 p = cpl_parameter_new_value("fors.fors_pmos_extract.flatfield", 00342 CPL_TYPE_BOOL, 00343 "Apply flat field", 00344 "fors.fors_pmos_extract", 00345 FALSE); 00346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield"); 00347 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00348 cpl_parameterlist_append(recipe->parameters, p); 00349 00350 /* 00351 * Global sky subtraction 00352 */ 00353 00354 p = cpl_parameter_new_value("fors.fors_pmos_extract.skyglobal", 00355 CPL_TYPE_BOOL, 00356 "Subtract global sky spectrum from CCD", 00357 "fors.fors_pmos_extract", 00358 FALSE); 00359 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyglobal"); 00360 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00361 cpl_parameterlist_append(recipe->parameters, p); 00362 00363 p = cpl_parameter_new_value("fors.fors_pmos_extract.skymedian", 00364 CPL_TYPE_BOOL, 00365 "Sky subtraction from extracted slit spectra", 00366 "fors.fors_pmos_extract", 00367 FALSE); 00368 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian"); 00369 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00370 cpl_parameterlist_append(recipe->parameters, p); 00371 00372 /* 00373 * Local sky subtraction on CCD spectra 00374 */ 00375 00376 p = cpl_parameter_new_value("fors.fors_pmos_extract.skylocal", 00377 CPL_TYPE_BOOL, 00378 "Sky subtraction from CCD slit spectra", 00379 "fors.fors_pmos_extract", 00380 TRUE); 00381 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal"); 00382 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00383 cpl_parameterlist_append(recipe->parameters, p); 00384 00385 /* 00386 * Cosmic rays removal 00387 */ 00388 00389 p = cpl_parameter_new_value("fors.fors_pmos_extract.cosmics", 00390 CPL_TYPE_BOOL, 00391 "Eliminate cosmic rays hits (only if global " 00392 "sky subtraction is also requested)", 00393 "fors.fors_pmos_extract", 00394 FALSE); 00395 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics"); 00396 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00397 cpl_parameterlist_append(recipe->parameters, p); 00398 00399 /* 00400 * Slit margin 00401 */ 00402 00403 p = cpl_parameter_new_value("fors.fors_pmos_extract.slit_margin", 00404 CPL_TYPE_INT, 00405 "Number of pixels to exclude at each slit " 00406 "in object detection and extraction", 00407 "fors.fors_pmos_extract", 00408 3); 00409 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin"); 00410 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00411 cpl_parameterlist_append(recipe->parameters, p); 00412 00413 /* 00414 * Extraction radius 00415 */ 00416 00417 p = cpl_parameter_new_value("fors.fors_pmos_extract.ext_radius", 00418 CPL_TYPE_INT, 00419 "Maximum extraction radius for detected " 00420 "objects (pixel)", 00421 "fors.fors_pmos_extract", 00422 6); 00423 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius"); 00424 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00425 cpl_parameterlist_append(recipe->parameters, p); 00426 00427 /* 00428 * Contamination radius 00429 */ 00430 00431 p = cpl_parameter_new_value("fors.fors_pmos_extract.cont_radius", 00432 CPL_TYPE_INT, 00433 "Minimum distance at which two objects " 00434 "of equal luminosity do not contaminate " 00435 "each other (pixel)", 00436 "fors.fors_pmos_extract", 00437 0); 00438 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius"); 00439 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00440 cpl_parameterlist_append(recipe->parameters, p); 00441 00442 /* 00443 * Object extraction method 00444 */ 00445 00446 p = cpl_parameter_new_value("fors.fors_pmos_extract.ext_mode", 00447 CPL_TYPE_INT, 00448 "Object extraction method: 0 = aperture, " 00449 "1 = Horne optimal extraction", 00450 "fors.fors_pmos_extract", 00451 1); 00452 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode"); 00453 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00454 cpl_parameterlist_append(recipe->parameters, p); 00455 00456 /* 00457 * Normalise output by exposure time 00458 */ 00459 00460 p = cpl_parameter_new_value("fors.fors_pmos_extract.time_normalise", 00461 CPL_TYPE_BOOL, 00462 "Normalise output spectra by the exposure time", 00463 "fors.fors_pmos_extract", 00464 TRUE); 00465 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise"); 00466 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00467 cpl_parameterlist_append(recipe->parameters, p); 00468 00469 /* 00470 * Apply chromatism correction to polarization angle 00471 */ 00472 00473 p = cpl_parameter_new_value("fors.fors_pmos_extract.chromatism", 00474 CPL_TYPE_BOOL, 00475 "Chromatism correction to polarization angles", 00476 "fors.fors_pmos_extract", 00477 TRUE); 00478 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "chromatism"); 00479 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00480 cpl_parameterlist_append(recipe->parameters, p); 00481 00482 /* 00483 * Create check products 00484 */ 00485 00486 p = cpl_parameter_new_value("fors.fors_pmos_extract.check", 00487 CPL_TYPE_BOOL, 00488 "Create intermediate products", 00489 "fors.fors_pmos_extract", 00490 FALSE); 00491 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check"); 00492 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00493 cpl_parameterlist_append(recipe->parameters, p); 00494 00495 return 0; 00496 } 00497 00498 00507 static int fors_pmos_extract_exec(cpl_plugin *plugin) 00508 { 00509 cpl_recipe *recipe; 00510 00511 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00512 recipe = (cpl_recipe *)plugin; 00513 else 00514 return -1; 00515 00516 return fors_pmos_extract(recipe->parameters, recipe->frames); 00517 } 00518 00519 00528 static int fors_pmos_extract_destroy(cpl_plugin *plugin) 00529 { 00530 cpl_recipe *recipe; 00531 00532 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00533 recipe = (cpl_recipe *)plugin; 00534 else 00535 return -1; 00536 00537 cpl_parameterlist_delete(recipe->parameters); 00538 00539 return 0; 00540 } 00541 00542 00552 static int fors_pmos_extract(cpl_parameterlist *parlist, cpl_frameset *frameset) 00553 { 00554 00555 const char *recipe = "fors_pmos_extract"; 00556 00557 00558 /* 00559 * Input parameters 00560 */ 00561 00562 double dispersion; 00563 int skyalign; 00564 const char *wcolumn; 00565 double startwavelength; 00566 double endwavelength; 00567 int flux; 00568 int flatfield; 00569 int skyglobal; 00570 int skylocal; 00571 int skymedian; 00572 int chromatism; 00573 int cosmics; 00574 int slit_margin; 00575 int ext_radius; 00576 int cont_radius; 00577 int ext_mode; 00578 int time_normalise; 00579 int check; 00580 00581 /* 00582 * CPL objects 00583 */ 00584 00585 cpl_image **images; 00586 00587 cpl_image **reduceds = NULL; 00588 cpl_image **rerrors = NULL; 00589 cpl_table **slitss = NULL; 00590 cpl_image **mappeds = NULL; 00591 cpl_image **skylocalmaps = NULL; 00592 00593 int nobjects = 0; 00594 00595 cpl_image *bias = NULL; 00596 cpl_image *norm_flat = NULL; 00597 cpl_image *spectra = NULL; 00598 cpl_image *rectified = NULL; 00599 cpl_image *coordinate = NULL; 00600 cpl_image *rainbow = NULL; 00601 cpl_image *mapped = NULL; 00602 cpl_image *mapped_sky = NULL; 00603 cpl_image *mapped_cleaned = NULL; 00604 cpl_image *smapped = NULL; 00605 cpl_image *wavemap = NULL; 00606 cpl_image *skymap = NULL; 00607 cpl_image *skylocalmap = NULL; 00608 cpl_image *dummy = NULL; 00609 00610 cpl_table *grism_table = NULL; 00611 cpl_table *overscans = NULL; 00612 cpl_table *wavelengths = NULL; 00613 cpl_table *idscoeff = NULL; 00614 cpl_table *slits = NULL; 00615 cpl_table *origslits = NULL; 00616 cpl_table *maskslits = NULL; 00617 cpl_table *polytraces = NULL; 00618 cpl_table *offsets = NULL; 00619 cpl_table *sky = NULL; 00620 00621 cpl_vector *lines = NULL; 00622 00623 cpl_propertylist *header = NULL; 00624 cpl_propertylist *save_header = NULL; 00625 00626 cpl_table *global = NULL; 00627 /* 00628 * Auxiliary variables 00629 */ 00630 00631 char version[80]; 00632 char *instrume = NULL; 00633 const char *science_tag; 00634 const char *master_norm_flat_tag; 00635 const char *disp_coeff_sky_tag; 00636 const char *wavelength_map_sky_tag; 00637 const char *reduced_science_tag; 00638 const char *reduced_sky_tag; 00639 const char *reduced_error_tag; 00640 const char *mapped_science_tag; 00641 const char *unmapped_science_tag; 00642 const char *mapped_science_sky_tag; 00643 const char *mapped_sky_tag; 00644 const char *unmapped_sky_tag; 00645 const char *global_sky_spectrum_tag; 00646 const char *object_table_tag; 00647 const char *object_table_pol_tag; 00648 const char *skylines_offsets_tag; 00649 const char *reduced_q_tag; 00650 const char *reduced_u_tag; 00651 const char *reduced_v_tag; 00652 const char *reduced_l_tag; 00653 const char *reduced_error_q_tag; 00654 const char *reduced_error_u_tag; 00655 const char *reduced_error_v_tag; 00656 const char *reduced_error_l_tag; 00657 const char *reduced_nul_q_tag; 00658 const char *reduced_nul_u_tag; 00659 const char *reduced_nul_v_tag; 00660 const char *reduced_angle_tag; 00661 const char *reduced_error_angle_tag; 00662 const char *master_distortion_tag = "MASTER_DISTORTION_TABLE"; 00663 const char *chrom_table_tag = "RETARDER_WAVEPLATE_CHROMATISM"; 00664 float *angles = NULL; 00665 int pmos, circ; 00666 int nscience; 00667 double alltime; 00668 double mean_rms; 00669 int nlines; 00670 int rebin; 00671 double *line; 00672 int nx = 0, ny; 00673 int ccd_xsize, ccd_ysize; 00674 double reference; 00675 double gain; 00676 double ron; 00677 int standard; 00678 int highres; 00679 int i, j; 00680 cpl_error_code error; 00681 00682 int * nobjs_per_slit; 00683 int nslits_out_det = 0; 00684 00685 00686 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00687 00688 cpl_msg_set_indentation(2); 00689 00690 if (dfs_files_dont_exist(frameset)) 00691 fors_pmos_extract_exit(NULL); 00692 00693 00694 /* 00695 * Get configuration parameters 00696 */ 00697 00698 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00699 cpl_msg_indent_more(); 00700 00701 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00702 fors_pmos_extract_exit("Too many in input: GRISM_TABLE"); 00703 00704 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00705 00706 dispersion = dfs_get_parameter_double(parlist, 00707 "fors.fors_pmos_extract.dispersion", grism_table); 00708 00709 if (dispersion <= 0.0) 00710 fors_pmos_extract_exit("Invalid resampling step"); 00711 00712 skyalign = dfs_get_parameter_int(parlist, 00713 "fors.fors_pmos_extract.skyalign", NULL); 00714 00715 if (skyalign > 2) 00716 fors_pmos_extract_exit("Max polynomial degree for sky alignment is 2"); 00717 00718 wcolumn = dfs_get_parameter_string(parlist, 00719 "fors.fors_pmos_extract.wcolumn", NULL); 00720 00721 startwavelength = dfs_get_parameter_double(parlist, 00722 "fors.fors_pmos_extract.startwavelength", grism_table); 00723 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00724 fors_pmos_extract_exit("Invalid wavelength"); 00725 00726 endwavelength = dfs_get_parameter_double(parlist, 00727 "fors.fors_pmos_extract.endwavelength", grism_table); 00728 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00729 fors_pmos_extract_exit("Invalid wavelength"); 00730 00731 if (endwavelength - startwavelength <= 0.0) 00732 fors_pmos_extract_exit("Invalid wavelength interval"); 00733 00734 flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flux", NULL); 00735 00736 flatfield = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flatfield", 00737 NULL); 00738 00739 skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skyglobal", 00740 NULL); 00741 skylocal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skylocal", 00742 NULL); 00743 skymedian = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skymedian", 00744 NULL); 00745 /* NSS 00746 skymedian = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.skymedian", 00747 NULL); 00748 */ 00749 00750 chromatism = 00751 dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.chromatism", 00752 NULL); 00753 00754 if (skylocal && skyglobal) 00755 fors_pmos_extract_exit("Cannot apply both local and global sky subtraction"); 00756 00757 if (skylocal && skymedian) 00758 fors_pmos_extract_exit("Cannot apply sky subtraction both on extracted " 00759 "and non-extracted spectra"); 00760 00761 cosmics = dfs_get_parameter_bool(parlist, 00762 "fors.fors_pmos_extract.cosmics", NULL); 00763 00764 if (cosmics) 00765 if (!(skyglobal || skylocal)) 00766 fors_pmos_extract_exit("Cosmic rays correction requires " 00767 "either skylocal=true or skyglobal=true"); 00768 00769 slit_margin = dfs_get_parameter_int(parlist, 00770 "fors.fors_pmos_extract.slit_margin", 00771 NULL); 00772 if (slit_margin < 0) 00773 fors_pmos_extract_exit("Value must be zero or positive"); 00774 00775 ext_radius = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_radius", 00776 NULL); 00777 if (ext_radius < 0) 00778 fors_pmos_extract_exit("Value must be zero or positive"); 00779 00780 cont_radius = dfs_get_parameter_int(parlist, 00781 "fors.fors_pmos_extract.cont_radius", 00782 NULL); 00783 if (cont_radius < 0) 00784 fors_pmos_extract_exit("Value must be zero or positive"); 00785 00786 ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_mode", 00787 NULL); 00788 if (ext_mode < 0 || ext_mode > 1) 00789 fors_pmos_extract_exit("Invalid object extraction mode"); 00790 00791 time_normalise = dfs_get_parameter_bool(parlist, 00792 "fors.fors_pmos_extract.time_normalise", NULL); 00793 00794 check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.check", NULL); 00795 cpl_table_delete(grism_table); grism_table = NULL; 00796 00797 if (cpl_error_get_code()) 00798 fors_pmos_extract_exit("Failure getting the configuration parameters"); 00799 00800 00801 /* 00802 * Check input set-of-frames 00803 */ 00804 00805 cpl_msg_indent_less(); 00806 cpl_msg_info(recipe, "Check input set-of-frames:"); 00807 cpl_msg_indent_more(); 00808 00809 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID")) 00810 fors_pmos_extract_exit("Input frames are not from the same grism"); 00811 00812 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID")) 00813 fors_pmos_extract_exit("Input frames are not from the same filter"); 00814 00815 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID")) 00816 fors_pmos_extract_exit("Input frames are not from the same chip"); 00817 00818 standard = 0; 00819 pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS"); 00820 00821 if (pmos == 0) { 00822 pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS"); 00823 standard = 1; 00824 } 00825 00826 if (pmos == 0) 00827 fors_pmos_extract_exit("Missing input scientific frame"); 00828 00829 angles = fors_check_angles(frameset, pmos, 00830 standard ? "STANDARD_PMOS" : "SCIENCE_PMOS", 00831 &circ); 00832 if (angles == NULL) 00833 fors_pmos_extract_exit("Polarization angles could not be read"); 00834 00835 if (circ) 00836 chromatism = 0; /* Chromatism correction unrequired for 00837 circular polarimetry */ 00838 00839 00840 nscience = pmos; 00841 00842 reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00843 rerrors = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00844 slitss = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience); 00845 mappeds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00846 skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00847 00848 if (pmos) { 00849 cpl_msg_info(recipe, "PMOS data found"); 00850 if (standard) { 00851 science_tag = "STANDARD_PMOS"; 00852 reduced_science_tag = "REDUCED_STD_PMOS"; 00853 unmapped_science_tag = "UNMAPPED_STD_PMOS"; 00854 mapped_science_tag = "MAPPED_STD_PMOS"; 00855 mapped_science_sky_tag = "MAPPED_ALL_STD_PMOS"; 00856 skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_PMOS"; 00857 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_PMOS"; 00858 disp_coeff_sky_tag = "DISP_COEFF_STD_PMOS"; 00859 mapped_sky_tag = "MAPPED_SKY_STD_PMOS"; 00860 unmapped_sky_tag = "UNMAPPED_SKY_STD_PMOS"; 00861 object_table_tag = "OBJECT_TABLE_STD_PMOS"; 00862 object_table_pol_tag = "OBJECT_TABLE_POL_STD_PMOS"; 00863 reduced_sky_tag = "REDUCED_SKY_STD_PMOS"; 00864 reduced_error_tag = "REDUCED_ERROR_STD_PMOS"; 00865 reduced_q_tag = "REDUCED_Q_STD_PMOS"; 00866 reduced_u_tag = "REDUCED_U_STD_PMOS"; 00867 reduced_v_tag = "REDUCED_V_STD_PMOS"; 00868 reduced_l_tag = "REDUCED_L_STD_PMOS"; 00869 reduced_error_q_tag = "REDUCED_ERROR_Q_STD_PMOS"; 00870 reduced_error_u_tag = "REDUCED_ERROR_U_STD_PMOS"; 00871 reduced_error_v_tag = "REDUCED_ERROR_V_STD_PMOS"; 00872 reduced_error_l_tag = "REDUCED_ERROR_L_STD_PMOS"; 00873 reduced_nul_q_tag = "REDUCED_NUL_Q_STD_PMOS"; 00874 reduced_nul_u_tag = "REDUCED_NUL_U_STD_PMOS"; 00875 reduced_nul_v_tag = "REDUCED_NUL_V_STD_PMOS"; 00876 reduced_angle_tag = "REDUCED_ANGLE_STD_PMOS"; 00877 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS"; 00878 } 00879 else { 00880 science_tag = "SCIENCE_PMOS"; 00881 reduced_science_tag = "REDUCED_SCI_PMOS"; 00882 unmapped_science_tag = "UNMAPPED_SCI_PMOS"; 00883 mapped_science_tag = "MAPPED_SCI_PMOS"; 00884 mapped_science_sky_tag = "MAPPED_ALL_SCI_PMOS"; 00885 skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_PMOS"; 00886 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_PMOS"; 00887 disp_coeff_sky_tag = "DISP_COEFF_SCI_PMOS"; 00888 mapped_sky_tag = "MAPPED_SKY_SCI_PMOS"; 00889 unmapped_sky_tag = "UNMAPPED_SKY_SCI_PMOS"; 00890 object_table_tag = "OBJECT_TABLE_SCI_PMOS"; 00891 object_table_pol_tag = "OBJECT_TABLE_POL_SCI_PMOS"; 00892 reduced_sky_tag = "REDUCED_SKY_SCI_PMOS"; 00893 reduced_error_tag = "REDUCED_ERROR_SCI_PMOS"; 00894 reduced_q_tag = "REDUCED_Q_SCI_PMOS"; 00895 reduced_u_tag = "REDUCED_U_SCI_PMOS"; 00896 reduced_v_tag = "REDUCED_V_SCI_PMOS"; 00897 reduced_l_tag = "REDUCED_L_SCI_PMOS"; 00898 reduced_error_q_tag = "REDUCED_ERROR_Q_SCI_PMOS"; 00899 reduced_error_u_tag = "REDUCED_ERROR_U_SCI_PMOS"; 00900 reduced_error_v_tag = "REDUCED_ERROR_V_SCI_PMOS"; 00901 reduced_error_l_tag = "REDUCED_ERROR_L_SCI_PMOS"; 00902 reduced_nul_q_tag = "REDUCED_NUL_Q_SCI_PMOS"; 00903 reduced_nul_u_tag = "REDUCED_NUL_U_SCI_PMOS"; 00904 reduced_nul_v_tag = "REDUCED_NUL_V_SCI_PMOS"; 00905 reduced_angle_tag = "REDUCED_ANGLE_SCI_PMOS"; 00906 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS"; 00907 } 00908 00909 master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS"; 00910 global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_PMOS"; 00911 00912 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) { 00913 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_PMOS"; 00914 } 00915 } 00916 00917 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) 00918 fors_pmos_extract_exit("Missing required input: MASTER_BIAS"); 00919 00920 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 00921 fors_pmos_extract_exit("Too many in input: MASTER_BIAS"); 00922 00923 if (skyalign >= 0) 00924 if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1) 00925 fors_pmos_extract_exit("Too many in input: MASTER_SKYLINECAT"); 00926 00927 if (chromatism) { 00928 if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) { 00929 cpl_msg_error(recipe, "Missing required input: %s", 00930 chrom_table_tag); 00931 fors_pmos_extract_exit(NULL); 00932 } 00933 00934 if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) { 00935 cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag); 00936 fors_pmos_extract_exit(NULL); 00937 } 00938 } 00939 00940 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) { 00941 if (flatfield) { 00942 cpl_msg_error(recipe, "Too many in input: %s", 00943 master_norm_flat_tag); 00944 fors_pmos_extract_exit(NULL); 00945 } 00946 else { 00947 cpl_msg_warning(recipe, "%s in input are ignored, " 00948 "since flat field correction was not requested", 00949 master_norm_flat_tag); 00950 } 00951 } 00952 00953 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) { 00954 if (!flatfield) { 00955 cpl_msg_warning(recipe, "%s in input is ignored, " 00956 "since flat field correction was not requested", 00957 master_norm_flat_tag); 00958 } 00959 } 00960 00961 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) { 00962 if (flatfield) { 00963 cpl_msg_error(recipe, "Flat field correction was requested, " 00964 "but no %s are found in input", 00965 master_norm_flat_tag); 00966 fors_pmos_extract_exit(NULL); 00967 } 00968 } 00969 00970 if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0) 00971 fors_pmos_extract_exit("Missing required input: MASTER_DISTORTION_TABLE"); 00972 00973 if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1) 00974 fors_pmos_extract_exit("Too many in input: MASTER_DISTORTION_TABLE"); 00975 00976 global = dfs_load_table(frameset, master_distortion_tag, 1); 00977 if (global == NULL) 00978 fors_pmos_extract_exit("Cannot load master distortion table"); 00979 00980 cpl_msg_indent_less(); 00981 00982 /* 00983 * Get the reference wavelength and the rebin factor along the 00984 * dispersion direction from a scientific exposure 00985 */ 00986 00987 header = dfs_load_header(frameset, science_tag, 0); 00988 00989 if (header == NULL) 00990 fors_pmos_extract_exit("Cannot load scientific frame header"); 00991 00992 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 00993 if (instrume == NULL) 00994 fors_pmos_extract_exit("Missing keyword INSTRUME in scientific header"); 00995 instrume = cpl_strdup(instrume); 00996 00997 if (instrume[4] == '1') 00998 snprintf(version, 80, "%s/%s", "fors1", VERSION); 00999 if (instrume[4] == '2') 01000 snprintf(version, 80, "%s/%s", "fors2", VERSION); 01001 01002 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 01003 01004 if (cpl_error_get_code() != CPL_ERROR_NONE) 01005 fors_pmos_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific " 01006 "frame header"); 01007 01008 if (reference < 3000.0) /* Perhaps in nanometers... */ 01009 reference *= 10; 01010 01011 if (reference < 3000.0 || reference > 13000.0) { 01012 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 01013 "keyword ESO INS GRIS1 WLEN in scientific frame header", 01014 reference); 01015 fors_pmos_extract_exit(NULL); 01016 } 01017 01018 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 01019 01020 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 01021 01022 if (cpl_error_get_code() != CPL_ERROR_NONE) 01023 fors_pmos_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific " 01024 "frame header"); 01025 01026 if (rebin != 1) { 01027 dispersion *= rebin; 01028 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01029 "resampling step used is %f A/pixel", rebin, 01030 dispersion); 01031 } 01032 01033 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01034 01035 if (cpl_error_get_code() != CPL_ERROR_NONE) 01036 fors_pmos_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific " 01037 "frame header"); 01038 01039 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 01040 01041 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON"); 01042 01043 if (cpl_error_get_code() != CPL_ERROR_NONE) 01044 fors_pmos_extract_exit("Missing keyword ESO DET OUT1 RON in scientific " 01045 "frame header"); 01046 01047 ron /= gain; /* Convert from electrons to ADU */ 01048 01049 cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron); 01050 01051 cpl_msg_info(recipe, "Load normalised flat field (if present)..."); 01052 cpl_msg_indent_more(); 01053 01054 if (flatfield) { 01055 norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 01056 CPL_TYPE_FLOAT, 0, 1); 01057 } 01058 01059 cpl_msg_info(recipe, "Produce mask slit position table..."); 01060 01061 maskslits = mos_load_slits_fors_pmos(header, &nslits_out_det); 01062 01063 if (skyalign >= 0) { 01064 01065 cpl_msg_indent_less(); 01066 cpl_msg_info(recipe, "Load input sky line catalog..."); 01067 cpl_msg_indent_more(); 01068 01069 wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1); 01070 01071 if (wavelengths) { 01072 /* 01073 * Cast the wavelengths into a (double precision) CPL vector 01074 */ 01075 01076 nlines = cpl_table_get_nrow(wavelengths); 01077 01078 if (nlines == 0) 01079 fors_pmos_extract_exit("Empty input sky line catalog"); 01080 01081 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 01082 cpl_msg_error(recipe, "Missing column %s in input line " 01083 "catalog table", wcolumn); 01084 fors_pmos_extract_exit(NULL); 01085 } 01086 01087 line = cpl_malloc(nlines * sizeof(double)); 01088 01089 for (i = 0; i < nlines; i++) 01090 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 01091 01092 cpl_table_delete(wavelengths); wavelengths = NULL; 01093 01094 lines = cpl_vector_wrap(nlines, line); 01095 } 01096 else { 01097 cpl_msg_info(recipe, "No sky line catalog found in input - fine!"); 01098 } 01099 } 01100 01101 01102 cpl_propertylist_delete(header); header = NULL; 01103 01104 /* 01105 * Load the wavelength calibration table 01106 */ 01107 01108 for (j = 0; j < nscience; j++) { 01109 int k; 01110 01111 cpl_msg_indent_less(); 01112 cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f " 01113 "(%d out of %d) ...", 01114 angles[j], j + 1, nscience); 01115 cpl_msg_indent_more(); 01116 01117 cpl_msg_info(recipe, "Load scientific exposure..."); 01118 cpl_msg_indent_more(); 01119 01120 /* 01121 * FIXME: Horrible workaround to avoid the problem because of the 01122 * multiple encapsulation of cpl_frameset_find() in different 01123 * loading functions 01124 */ 01125 01126 header = dfs_load_header(frameset, science_tag, 0); 01127 01128 for (k = 0; k < j; k ++) { 01129 cpl_propertylist_delete(header); 01130 header = dfs_load_header(frameset, NULL, 0); 01131 } 01132 01133 spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0); 01134 01135 for (k = 0; k < j; k ++) { 01136 cpl_image_delete(spectra); 01137 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01138 } 01139 01140 if (spectra == NULL) 01141 fors_pmos_extract_exit("Cannot load scientific frame"); 01142 01143 if (header == NULL) 01144 fors_pmos_extract_exit("Cannot load scientific frame header"); 01145 01146 alltime = cpl_propertylist_get_double(header, "EXPTIME"); 01147 01148 if (cpl_error_get_code() != CPL_ERROR_NONE) 01149 fors_pmos_extract_exit("Missing keyword EXPTIME in scientific " 01150 "frame header"); 01151 01152 /* Leave the header on for the next step... */ 01153 //cpl_propertylist_delete(header); header = NULL; 01154 01155 cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 01156 alltime); 01157 01158 cpl_msg_indent_less(); 01159 01160 /* 01161 * Remove the master bias 01162 */ 01163 01164 cpl_msg_info(recipe, "Remove the master bias..."); 01165 01166 bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1); 01167 01168 if (bias == NULL) 01169 fors_pmos_extract_exit("Cannot load master bias"); 01170 01171 overscans = mos_load_overscans_vimos(header, 1); 01172 01173 dummy = mos_remove_bias(spectra, bias, overscans); 01174 cpl_image_delete(spectra); spectra = dummy; dummy = NULL; 01175 cpl_image_delete(bias); bias = NULL; 01176 cpl_table_delete(overscans); overscans = NULL; 01177 01178 if (spectra == NULL) 01179 fors_pmos_extract_exit("Cannot remove bias from scientific frame"); 01180 01181 ccd_xsize = nx = cpl_image_get_size_x(spectra); 01182 ccd_ysize = ny = cpl_image_get_size_y(spectra); 01183 01184 if (flatfield) { 01185 01186 if (norm_flat) { 01187 cpl_msg_info(recipe, "Apply flat field correction..."); 01188 if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) { 01189 cpl_msg_error(recipe, "Failure of flat field correction: %s", 01190 cpl_error_get_message()); 01191 fors_pmos_extract_exit(NULL); 01192 } 01193 } 01194 else { 01195 cpl_msg_error(recipe, "Cannot load input %s for flat field " 01196 "correction", master_norm_flat_tag); 01197 fors_pmos_extract_exit(NULL); 01198 } 01199 01200 } 01201 01202 /* 01203 * Load the slit location table 01204 */ 01205 01206 slits = mos_build_slit_location(global, maskslits, ny); 01207 01208 if (slits == NULL) { 01209 fors_pmos_extract_exit("Cannot load slits location table"); 01210 } else { 01211 cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT); 01212 01213 int m, null, size = cpl_table_get_nrow(slits); 01214 01215 for (m = 0; m < size; m++) { 01216 int slit_id = cpl_table_get(slits, "slit_id", m, &null); 01217 01218 int pair_id = slit_id % 2 ? slit_id + 1 : slit_id; 01219 01220 cpl_table_set(slits, "pair_id", m, pair_id); 01221 } 01222 } 01223 01224 cpl_msg_info(recipe, "Processing scientific spectra..."); 01225 01226 /* 01227 * Load the spectral curvature table 01228 */ 01229 01230 polytraces = mos_build_curv_coeff(global, maskslits, slits); 01231 if (polytraces == NULL) 01232 fors_pmos_extract_exit("Cannot create spectral curvature table"); 01233 01234 /* 01235 * This one will also generate the spatial map from the spectral 01236 * curvature table (in the case of multislit data) 01237 */ 01238 01239 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01240 01241 smapped = mos_spatial_calibration(spectra, slits, polytraces, reference, 01242 startwavelength, endwavelength, 01243 dispersion, flux, coordinate); 01244 01245 /* 01246 * Generate a rectified wavelength map from the wavelength calibration 01247 * table 01248 */ 01249 01250 /* 01251 * Load the wavelength calibration table 01252 */ 01253 01254 idscoeff = mos_build_disp_coeff(global, slits); 01255 if (idscoeff == NULL) 01256 fors_pmos_extract_exit("Cannot create wavelength calibration table"); 01257 01258 rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 01259 endwavelength); 01260 01261 if (dispersion > 1.0) 01262 highres = 0; 01263 else 01264 highres = 1; 01265 01266 if (skyalign >= 0) { 01267 if (skyalign) { 01268 cpl_msg_info(recipe, "Align wavelength solution to reference " 01269 "skylines applying %d order residual fit...", skyalign); 01270 } 01271 else { 01272 cpl_msg_info(recipe, "Align wavelength solution to reference " 01273 "skylines applying median offset..."); 01274 } 01275 01276 if (!j) { 01277 offsets = mos_wavelength_align(smapped, slits, reference, 01278 startwavelength, endwavelength, 01279 idscoeff, lines, highres, 01280 skyalign, rainbow, 4); 01281 01282 if (offsets) { 01283 if (standard) 01284 cpl_msg_warning(recipe, "Alignment of the wavelength solution " 01285 "to reference sky lines may be unreliable in " 01286 "this case!"); 01287 01288 if (dfs_save_table(frameset, offsets, skylines_offsets_tag, 01289 NULL, parlist, recipe, version)) { 01290 fors_pmos_extract_exit(NULL); 01291 } 01292 01293 } else { 01294 cpl_msg_warning(recipe, "Alignment of the wavelength solution " 01295 "to reference sky lines could not be done!"); 01296 skyalign = -1; 01297 } 01298 } 01299 01300 01301 } 01302 01303 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 01304 polytraces, reference, 01305 startwavelength, endwavelength, 01306 dispersion); 01307 01308 01309 cpl_image_delete(rainbow); rainbow = NULL; 01310 cpl_image_delete(coordinate); coordinate = NULL; 01311 01312 /* 01313 * Here the wavelength calibrated slit spectra are created. This frame 01314 * contains sky_science. 01315 */ 01316 01317 mapped_sky = mos_wavelength_calibration(smapped, reference, 01318 startwavelength, endwavelength, 01319 dispersion, idscoeff, flux); 01320 01321 if (!j) { 01322 cpl_msg_indent_less(); 01323 cpl_msg_info(recipe, "Check applied wavelength against skylines..."); 01324 cpl_msg_indent_more(); 01325 01326 mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength, 01327 dispersion, 6, highres); 01328 01329 01330 cpl_msg_info(recipe, "Mean residual: %f", mean_rms); 01331 01332 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01333 01334 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 01335 mean_rms, mean_rms * dispersion); 01336 } 01337 01338 save_header = cpl_propertylist_duplicate(header); 01339 01340 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01341 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01342 cpl_propertylist_update_double(header, "CRVAL1", 01343 startwavelength + dispersion/2); 01344 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01345 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01346 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01347 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01348 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01349 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01350 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01351 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01352 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01353 01354 if (time_normalise) { 01355 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime); 01356 if (!j) { 01357 if(dfs_save_image_null(frameset, parlist, 01358 mapped_science_sky_tag, 01359 recipe, version)) { 01360 fors_pmos_extract_exit(NULL); 01361 } 01362 } 01363 if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) { 01364 fors_pmos_extract_exit(NULL); 01365 } 01366 cpl_image_delete(dummy); dummy = NULL; 01367 } 01368 else { 01369 01370 if (!j) { 01371 if(dfs_save_image_null(frameset, parlist, 01372 mapped_science_sky_tag, 01373 recipe, version)) { 01374 fors_pmos_extract_exit(NULL); 01375 } 01376 } 01377 01378 if (dfs_save_image_ext(mapped_sky, 01379 mapped_science_sky_tag, header)) { 01380 fors_pmos_extract_exit(NULL); 01381 } 01382 01383 } 01384 01385 /* if (skyglobal == 0 && skymedian < 0) { NSS */ 01386 if (skyglobal == 0 && skymedian == 0 && skylocal == 0) { 01387 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01388 } 01389 01390 if (skyglobal || skylocal) { 01391 01392 cpl_msg_indent_less(); 01393 01394 if (skyglobal) { 01395 cpl_msg_info(recipe, "Global sky determination..."); 01396 cpl_msg_indent_more(); 01397 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01398 01399 sky = mos_sky_map_super(spectra, wavemap, dispersion, 01400 2.0, 50, skymap); 01401 01402 if (sky) { 01403 cpl_image_subtract(spectra, skymap); 01404 } 01405 else { 01406 cpl_image_delete(skymap); skymap = NULL; 01407 } 01408 } 01409 else { 01410 cpl_msg_info(recipe, "Local sky determination..."); 01411 cpl_msg_indent_more(); 01412 skymap = mos_subtract_sky(spectra, slits, polytraces, reference, 01413 startwavelength, endwavelength, dispersion); 01414 } 01415 01416 if (skymap) { 01417 if (skyglobal) { 01418 if (time_normalise) 01419 cpl_table_divide_scalar(sky, "sky", alltime); 01420 01421 /* Old saving: 01422 01423 if (!j) { 01424 if (dfs_save_table(frameset, sky, 01425 global_sky_spectrum_tag, 01426 NULL, parlist, recipe, version)) { 01427 fors_pmos_extract_exit(NULL); 01428 } 01429 } else { 01430 if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 01431 NULL)) { 01432 fors_pmos_extract_exit(NULL); 01433 } 01434 } 01435 01436 End of old saving */ 01437 01438 if (!j) { 01439 if(dfs_save_image_null(frameset, parlist, 01440 global_sky_spectrum_tag, 01441 recipe, version)) { 01442 fors_pmos_extract_exit(NULL); 01443 } 01444 } 01445 01446 if (dfs_save_table_ext(sky, global_sky_spectrum_tag, 01447 NULL)) { 01448 fors_pmos_extract_exit(NULL); 01449 } 01450 01451 01452 cpl_table_delete(sky); sky = NULL; 01453 } 01454 01455 // save_header = dfs_load_header(frameset, science_tag, 0); 01456 01457 if (time_normalise) 01458 cpl_image_divide_scalar(skymap, alltime); 01459 01460 if (!j) { 01461 if(dfs_save_image_null(frameset, parlist, 01462 unmapped_sky_tag, 01463 recipe, version)) { 01464 fors_pmos_extract_exit(NULL); 01465 } 01466 } 01467 01468 if (dfs_save_image_ext(skymap, unmapped_sky_tag, 01469 save_header)) { 01470 fors_pmos_extract_exit(NULL); 01471 } 01472 01473 cpl_image_delete(skymap); skymap = NULL; 01474 01475 if (!j) { 01476 if(dfs_save_image_null(frameset, parlist, 01477 unmapped_science_tag, 01478 recipe, version)) { 01479 fors_pmos_extract_exit(NULL); 01480 } 01481 } 01482 01483 if (dfs_save_image_ext(spectra, unmapped_science_tag, 01484 save_header)) { 01485 fors_pmos_extract_exit(NULL); 01486 } 01487 01488 // cpl_propertylist_delete(save_header); save_header = NULL; 01489 01490 if (cosmics) { 01491 cpl_msg_info(recipe, "Removing cosmic rays..."); 01492 mos_clean_cosmics(spectra, gain, -1., -1.); 01493 } 01494 01495 /* 01496 * The spatially rectified image, that contained the sky, 01497 * is replaced by a sky-subtracted spatially rectified image: 01498 */ 01499 01500 cpl_image_delete(smapped); smapped = NULL; 01501 01502 smapped = mos_spatial_calibration(spectra, slits, polytraces, 01503 reference, startwavelength, 01504 endwavelength, dispersion, 01505 flux, NULL); 01506 } 01507 else { 01508 cpl_msg_warning(recipe, "Sky subtraction failure"); 01509 if (cosmics) 01510 cpl_msg_warning(recipe, "Cosmic rays removal not performed!"); 01511 cosmics = skylocal = skyglobal = 0; 01512 } 01513 } 01514 01515 cpl_image_delete(spectra); spectra = NULL; 01516 cpl_table_delete(polytraces); polytraces = NULL; 01517 01518 if (skyalign >= 0) { 01519 save_header = dfs_load_header(frameset, science_tag, 0); 01520 01521 if (!j) { 01522 if(dfs_save_image_null(frameset, parlist, 01523 wavelength_map_sky_tag, 01524 recipe, version)) { 01525 fors_pmos_extract_exit(NULL); 01526 } 01527 } 01528 01529 if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag, 01530 save_header)) { 01531 fors_pmos_extract_exit(NULL); 01532 } 01533 01534 // cpl_propertylist_delete(save_header); save_header = NULL; 01535 } 01536 01537 cpl_image_delete(wavemap); wavemap = NULL; 01538 01539 mapped = mos_wavelength_calibration(smapped, reference, 01540 startwavelength, endwavelength, 01541 dispersion, idscoeff, flux); 01542 01543 cpl_image_delete(smapped); smapped = NULL; 01544 01545 if (skyalign >= 0) { 01546 if (!j) { 01547 if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag, 01548 NULL, parlist, recipe, version)) { 01549 fors_pmos_extract_exit(NULL); 01550 } 01551 } 01552 } 01553 01554 /* if (skymedian >= 0) { NSS */ 01555 if (skymedian) { 01556 cpl_msg_indent_less(); 01557 cpl_msg_info(recipe, "Local sky determination..."); 01558 cpl_msg_indent_more(); 01559 01560 /* NSS skylocalmap = mos_sky_local(mapped, slits, skymedian); */ 01561 /* skylocalmap = mos_sky_local(mapped, slits, 0); */ 01562 skylocalmap = mos_sky_local_old(mapped, slits); 01563 cpl_image_subtract(mapped, skylocalmap); 01564 /* 01565 if (dfs_save_image(frameset, skylocalmap, mapped_sky_tag, header, 01566 parlist, recipe, version)) 01567 fors_pmos_extract_exit(NULL); 01568 */ 01569 cpl_image_delete(skylocalmap); skylocalmap = NULL; 01570 } 01571 01572 /* if (skyglobal || skymedian >= 0 || skylocal) { NSS */ 01573 if (skyglobal || skymedian || skylocal) { 01574 01575 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped); 01576 01577 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01578 01579 if (time_normalise) { 01580 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime); 01581 01582 if (!j) { 01583 if(dfs_save_image_null(frameset, parlist, 01584 mapped_sky_tag, 01585 recipe, version)) { 01586 fors_pmos_extract_exit(NULL); 01587 } 01588 } 01589 01590 if (dfs_save_image_ext(dummy, mapped_sky_tag, 01591 header)) { 01592 fors_pmos_extract_exit(NULL); 01593 } 01594 01595 cpl_image_delete(dummy); dummy = NULL; 01596 } 01597 else { 01598 if (!j) { 01599 if(dfs_save_image_null(frameset, parlist, 01600 mapped_sky_tag, 01601 recipe, version)) { 01602 fors_pmos_extract_exit(NULL); 01603 } 01604 } 01605 01606 if (dfs_save_image_ext(skylocalmap, mapped_sky_tag, 01607 header)) { 01608 fors_pmos_extract_exit(NULL); 01609 } 01610 } 01611 01612 skylocalmaps[j] = skylocalmap; 01613 01614 cpl_msg_indent_less(); 01615 cpl_msg_info(recipe, "Object detection..."); 01616 cpl_msg_indent_more(); 01617 01618 if (!j) 01619 origslits = cpl_table_duplicate(slits); 01620 01621 if (cosmics || nscience > 1) { 01622 dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius, 01623 cont_radius); 01624 } 01625 else { 01626 mapped_cleaned = cpl_image_duplicate(mapped); 01627 mos_clean_cosmics(mapped_cleaned, gain, -1., -1.); 01628 dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 01629 ext_radius, cont_radius); 01630 01631 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL; 01632 } 01633 01634 cpl_image_delete(dummy); dummy = NULL; 01635 01636 if (check) { 01637 01638 /* Old saving: 01639 01640 if (!j) { 01641 if (dfs_save_table(frameset, slits, object_table_tag, 01642 NULL, parlist, recipe, version)) { 01643 fors_pmos_extract_exit(NULL); 01644 } 01645 } else { 01646 if (dfs_save_table_ext(slits, object_table_tag, NULL)) { 01647 fors_pmos_extract_exit(NULL); 01648 } 01649 } 01650 01651 End old saving */ 01652 01653 if (!j) { 01654 if(dfs_save_image_null(frameset, parlist, 01655 object_table_tag, 01656 recipe, version)) { 01657 fors_pmos_extract_exit(NULL); 01658 } 01659 } 01660 01661 if (dfs_save_table_ext(slits, object_table_tag, NULL)) { 01662 fors_pmos_extract_exit(NULL); 01663 } 01664 } 01665 } 01666 01667 slitss[j] = slits; 01668 mappeds[j] = mapped; 01669 01670 cpl_msg_indent_less(); 01671 01672 cpl_propertylist_delete(header); header = NULL; 01673 cpl_propertylist_delete(save_header); save_header = NULL; 01674 01675 cpl_table_delete(idscoeff); idscoeff = NULL; 01676 } 01677 01678 cpl_table_delete(offsets); offsets = NULL; 01679 01680 cpl_image_delete(norm_flat); norm_flat = NULL; 01681 cpl_vector_delete(lines); lines = NULL; 01682 01683 cpl_table_delete(maskslits); maskslits = NULL; 01684 01685 01686 cpl_msg_indent_less(); 01687 cpl_msg_info(recipe, 01688 "Check object detection in both beams for all angles..."); 01689 cpl_msg_indent_more(); 01690 01691 /* House keeping - selection of objects for which information required 01692 for Stokes parameters computation is present */ 01693 error = mos_object_intersect(slitss, origslits, nscience, 5.0); 01694 if (error == CPL_ERROR_DATA_NOT_FOUND) { 01695 cpl_msg_warning(recipe, "No objects found: no Stokes " 01696 "parameters to compute!"); 01697 for (j = 0; j < nscience; j++) 01698 cpl_table_delete(slitss[j]); 01699 cpl_free(slitss); 01700 cpl_table_delete(origslits); 01701 return 0; 01702 } else if (error) { 01703 fors_pmos_extract_exit("Problem in polarimetric object selection"); 01704 } 01705 01706 if (dfs_save_table(frameset, origslits, object_table_pol_tag, 01707 NULL, parlist, recipe, version)) { 01708 fors_pmos_extract_exit(NULL); 01709 } 01710 01711 nobjs_per_slit = fors_get_nobjs_perslit(origslits); 01712 01713 cpl_msg_indent_less(); 01714 cpl_msg_info(recipe, "Object extraction..."); 01715 cpl_msg_indent_more(); 01716 01717 for (j = 0; j < nscience; j++) { 01718 int k; 01719 01720 header = dfs_load_header(frameset, science_tag, 0); 01721 01722 for (k = 0; k < j; k ++) { 01723 cpl_propertylist_delete(header); 01724 header = dfs_load_header(frameset, NULL, 0); 01725 } 01726 01727 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01728 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01729 cpl_propertylist_update_double(header, "CRVAL1", 01730 startwavelength + dispersion/2); 01731 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01732 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01733 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01734 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01735 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01736 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01737 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01738 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01739 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01740 01741 if (skyglobal || skymedian || skylocal) { 01742 01743 cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...", 01744 angles[j], j + 1, nscience); 01745 01746 images = mos_extract_objects(mappeds[j], skylocalmaps[j], 01747 origslits, 01748 ext_mode, ron, gain, 1); 01749 01750 cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL; 01751 01752 if (images) { 01753 if (time_normalise) 01754 cpl_image_divide_scalar(images[0], alltime); 01755 01756 if (!j) { 01757 if(dfs_save_image_null(frameset, parlist, 01758 reduced_science_tag, 01759 recipe, version)) { 01760 fors_pmos_extract_exit(NULL); 01761 } 01762 } 01763 01764 if (dfs_save_image_ext(images[0], reduced_science_tag, 01765 header)) { 01766 fors_pmos_extract_exit(NULL); 01767 } 01768 01769 reduceds[j] = images[0]; 01770 // cpl_image_delete(images[0]); 01771 01772 if (time_normalise) 01773 cpl_image_divide_scalar(images[1], alltime); 01774 01775 if (!j) { 01776 if(dfs_save_image_null(frameset, parlist, 01777 reduced_sky_tag, 01778 recipe, version)) { 01779 fors_pmos_extract_exit(NULL); 01780 } 01781 } 01782 01783 if (dfs_save_image_ext(images[1], reduced_sky_tag, 01784 header)) { 01785 fors_pmos_extract_exit(NULL); 01786 } 01787 cpl_image_delete(images[1]); 01788 01789 if (time_normalise) 01790 cpl_image_divide_scalar(images[2], alltime); 01791 01792 if (!j) { 01793 if(dfs_save_image_null(frameset, parlist, 01794 reduced_error_tag, 01795 recipe, version)) { 01796 fors_pmos_extract_exit(NULL); 01797 } 01798 } 01799 01800 if (dfs_save_image_ext(images[2], reduced_error_tag, 01801 header)) { 01802 fors_pmos_extract_exit(NULL); 01803 } 01804 01805 rerrors[j] = images[2]; 01806 // cpl_image_delete(images[2]); 01807 01808 cpl_free(images); 01809 } 01810 else { 01811 cpl_msg_warning(recipe, "No objects found: the products " 01812 "%s, %s, and %s are not created", 01813 reduced_science_tag, reduced_sky_tag, 01814 reduced_error_tag); 01815 } 01816 01817 } 01818 01819 // slitss[j] = slits; 01820 // cpl_table_delete(slits); slits = NULL; 01821 01822 01823 /* if (skyglobal || skymedian >= 0) { NSS */ 01824 if (skyglobal || skymedian || skylocal) { 01825 if (time_normalise) 01826 cpl_image_divide_scalar(mappeds[j], alltime); 01827 01828 if (!j) { 01829 if(dfs_save_image_null(frameset, parlist, 01830 mapped_science_tag, 01831 recipe, version)) { 01832 fors_pmos_extract_exit(NULL); 01833 } 01834 } 01835 01836 if (dfs_save_image_ext(mappeds[j], mapped_science_tag, 01837 header)) { 01838 fors_pmos_extract_exit(NULL); 01839 } 01840 } 01841 01842 cpl_image_delete(mappeds[j]); mappeds[j] = NULL; 01843 cpl_propertylist_delete(header); header = NULL; 01844 01845 } 01846 01847 cpl_table_delete(origslits); 01848 01849 /* Stokes computation */ 01850 01851 nobjects = cpl_image_get_size_y(reduceds[0]) / 2; 01852 nx = cpl_image_get_size_x(reduceds[0]); 01853 01854 header = cpl_propertylist_new(); 01855 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01856 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01857 cpl_propertylist_update_double(header, "CRVAL1", 01858 startwavelength + dispersion/2); 01859 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01860 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 01861 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 01862 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01863 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01864 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01865 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01866 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01867 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01868 01869 if (circ) { 01870 01871 cpl_image *pv_im = NULL; 01872 cpl_image *pvnull_im = NULL; 01873 cpl_image *perr_im = NULL; 01874 01875 double *p_v = NULL; 01876 double *p_vnull = NULL; 01877 double *perr = NULL; 01878 01879 double mean_vnull; 01880 01881 int p = -1; 01882 int total = 0; 01883 01884 pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 01885 perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 01886 01887 p_v = cpl_image_get_data_double(pv_im); 01888 perr = cpl_image_get_data_double(perr_im); 01889 01890 if (nscience / 2 > 1) { 01891 pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 01892 p_vnull = cpl_image_get_data_double(pvnull_im); 01893 } 01894 01895 for (j = 0; j < nobjects; j++) { 01896 int k, m; 01897 01898 double * ip_v, 01899 * ip_vnull, * iperr; 01900 01901 float * data; 01902 float * iff, * ierr; 01903 01904 ip_v = p_v + (nobjects - 1 - j) * nx; 01905 01906 if (nscience / 2 > 1) 01907 ip_vnull = p_vnull + (nobjects - 1 - j) * nx; 01908 01909 iperr = perr + (nobjects - 1 - j) * nx; 01910 01911 while (total < j + 1) { 01912 p++; 01913 total += nobjs_per_slit[p]; 01914 } 01915 01916 for (k = 0; k < nscience / 2; k++) { 01917 float * if_o, * if_e, * ifdelta_o, * ifdelta_e; 01918 01919 int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45); 01920 int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45); 01921 01922 data = cpl_image_get_data_float(reduceds[pos]); 01923 01924 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 01925 + (total - j - 1)) * nx; 01926 01927 if_e = data + (2 * (nobjects - total) 01928 + (total - j - 1)) * nx; 01929 01930 // if_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 01931 // if_e = data + 2 * (nobjects - 1 - j) * nx; 01932 01933 data = cpl_image_get_data_float(reduceds[pos_d]); 01934 01935 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 01936 + (total - j - 1)) * nx; 01937 01938 ifdelta_e = data + (2 * (nobjects - total) 01939 + (total - j - 1)) * nx; 01940 01941 // ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 01942 // ifdelta_e = data + 2 * (nobjects - 1 - j) * nx; 01943 01944 for (m = 0; m < nx; m++) { 01945 01946 double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 : 01947 (if_o[m] - if_e[m] ) / 01948 (if_o[m] + if_e[m] ) - 01949 (ifdelta_o[m] - ifdelta_e[m]) / 01950 (ifdelta_o[m] + ifdelta_e[m]); 01951 01952 quantity = isfinite(quantity) ? quantity : 0.0; 01953 01954 /* PQ map computation */ 01955 ip_v[m] += quantity * 0.5 / (nscience / 2); 01956 01957 /* PQnull map computation */ 01958 if (nscience / 2 > 1) { 01959 if (k % 2) 01960 ip_vnull[m] += quantity * 0.5 / (nscience / 2); 01961 else 01962 ip_vnull[m] -= quantity * 0.5 / (nscience / 2); 01963 } 01964 } 01965 } 01966 01967 /* Error map */ 01968 data = cpl_image_get_data_float(reduceds[0]); 01969 iff = data + 2 * (nobjects - 1 - j) * nx; 01970 01971 data = cpl_image_get_data_float(rerrors[0]); 01972 ierr = data + 2 * (nobjects - 1 - j) * nx; 01973 01974 for (m = 0; m < nx; m++) 01975 iperr[m] = iff[m] <= 0.0 ? 01976 0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2); 01977 01978 if (nscience / 2 > 1) { 01979 float * weights; 01980 float max, sum, sum2, imean; 01981 01982 int k; 01983 01984 /* QC on U NULL */ 01985 weights = cpl_malloc(sizeof(float) * nx); 01986 01987 max = 0.0; 01988 for (k = 0; k < nx; k++) { 01989 if (max < iff[k]) max = iff[k]; 01990 } 01991 01992 for (k = 0; k < nx; k++) { 01993 weights[k] = iff[k] < 0.0 ? 01994 0.0 : iff[k] * iff[k] / (max * max); 01995 } 01996 01997 sum = 0.0; 01998 sum2 = 0.0; 01999 for (k = 0; k < nx; k++) { 02000 sum += weights[k] * ip_vnull[k]; 02001 sum2 += weights[k]; 02002 } 02003 02004 cpl_free(weights); 02005 02006 imean = sum / sum2; 02007 02008 mean_vnull += (imean - mean_vnull) / (j + 1.0); 02009 } 02010 } 02011 02012 if (dfs_save_image(frameset, pv_im, reduced_v_tag, header, 02013 parlist, recipe, version)) 02014 fors_pmos_extract_exit(NULL); 02015 02016 if (nscience / 2 > 1) { 02017 char * pipefile, * keyname; 02018 cpl_propertylist * qheader = dfs_load_header(frameset, science_tag, 0); 02019 02020 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 02021 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 02022 cpl_propertylist_update_double(qheader, "CRVAL1", 02023 startwavelength + dispersion/2); 02024 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 02025 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02026 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02027 cpl_propertylist_update_double(qheader, "CD1_1", dispersion); 02028 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 02029 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 02030 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 02031 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 02032 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 02033 02034 fors_qc_start_group(qheader, "2.0", instrume); 02035 02036 /* 02037 * QC1 group header 02038 */ 02039 02040 if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag, 02041 "Product category", instrume)) 02042 fors_pmos_extract_exit("Cannot write product category to " 02043 "QC log file"); 02044 02045 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 02046 "DPR type", instrume)) 02047 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc " 02048 "lamp header"); 02049 02050 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 02051 "Template", instrume)) 02052 fors_pmos_extract_exit("Missing keyword TPL ID in arc " 02053 "lamp header"); 02054 02055 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 02056 "Grism name", instrume)) 02057 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc " 02058 "lamp header"); 02059 02060 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 02061 "Grism identifier", instrume)) 02062 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc " 02063 "lamp header"); 02064 02065 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 02066 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 02067 "Filter name", instrume); 02068 02069 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 02070 "Collimator name", instrume)) 02071 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc " 02072 "lamp header"); 02073 02074 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 02075 "Chip identifier", instrume)) 02076 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc " 02077 "lamp header"); 02078 02079 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 02080 "Archive name of input data", 02081 instrume)) 02082 fors_pmos_extract_exit("Missing keyword ARCFILE in arc " 02083 "lamp header"); 02084 02085 pipefile = dfs_generate_filename_tfits(reduced_nul_v_tag); 02086 if (fors_qc_write_string("PIPEFILE", pipefile, 02087 "Pipeline product name", instrume)) 02088 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file"); 02089 cpl_free(pipefile); pipefile = NULL; 02090 02091 02092 /* 02093 * QC1 parameters 02094 */ 02095 02096 keyname = "QC.NULL.V.MEAN"; 02097 02098 if (fors_qc_write_qc_double(qheader, mean_vnull, 02099 keyname, NULL, 02100 "Mean V null parameter", 02101 instrume)) { 02102 fors_pmos_extract_exit("Cannot write mean Q null parameter " 02103 "to QC log file"); 02104 } 02105 02106 fors_qc_end_group(); 02107 02108 if (dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader, 02109 parlist, recipe, version)) 02110 fors_pmos_extract_exit(NULL); 02111 02112 cpl_propertylist_delete(qheader); 02113 } 02114 02115 if (dfs_save_image(frameset, perr_im, reduced_error_v_tag, header, 02116 parlist, recipe, version)) 02117 fors_pmos_extract_exit(NULL); 02118 02119 cpl_image_delete(pv_im); 02120 cpl_image_delete(pvnull_im); 02121 cpl_image_delete(perr_im); 02122 } else { 02123 cpl_image *pq_im = NULL; 02124 cpl_image *pu_im = NULL; 02125 cpl_image *pl_im = NULL; 02126 02127 cpl_image *pqnull_im = NULL; 02128 cpl_image *punull_im = NULL; 02129 02130 cpl_image *pqerr_im = NULL; 02131 cpl_image *puerr_im = NULL; 02132 cpl_image *plerr_im = NULL; 02133 02134 cpl_image *pang_im = NULL; 02135 cpl_image *pangerr_im = NULL; 02136 02137 double *p_q = NULL; 02138 double *p_u = NULL; 02139 double *p_l = NULL; 02140 02141 double *p_qnull = NULL; 02142 double *p_unull = NULL; 02143 02144 double *pqerr = NULL; 02145 double *puerr = NULL; 02146 double *plerr = NULL; 02147 02148 double *pang = NULL; 02149 double *pangerr = NULL; 02150 02151 int k, m; 02152 02153 cpl_image * correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE); 02154 double * correct = cpl_image_get_data_double(correct_im); 02155 02156 double mean_unull, mean_qnull; 02157 02158 int p = -1; 02159 int total = 0; 02160 02161 pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02162 pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02163 pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02164 02165 pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02166 puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02167 plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02168 02169 pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02170 pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02171 02172 p_q = cpl_image_get_data_double(pq_im); 02173 p_u = cpl_image_get_data_double(pu_im); 02174 p_l = cpl_image_get_data_double(pl_im); 02175 02176 if (nscience / 4 > 1) { 02177 pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02178 punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02179 02180 p_qnull = cpl_image_get_data_double(pqnull_im); 02181 p_unull = cpl_image_get_data_double(punull_im); 02182 } else { 02183 cpl_msg_warning(cpl_func, 02184 "Not enough pairs to compute null parameters"); 02185 } 02186 02187 pqerr = cpl_image_get_data_double(pqerr_im); 02188 puerr = cpl_image_get_data_double(puerr_im); 02189 plerr = cpl_image_get_data_double(plerr_im); 02190 02191 pang = cpl_image_get_data_double(pang_im); 02192 pangerr = cpl_image_get_data_double(pangerr_im); 02193 02194 if (chromatism) { 02195 cpl_table * chrotbl = 02196 dfs_load_table(frameset, chrom_table_tag, 1); 02197 02198 int nrow = cpl_table_get_nrow(chrotbl); 02199 float * lambda = cpl_table_get_data_float(chrotbl, "lambda"); 02200 float * theta = cpl_table_get_data_float(chrotbl, "eps_theta"); 02201 02202 for (j = 0; j < nx; j++) { 02203 double c_wave = 02204 startwavelength + dispersion / 2 + j * dispersion; 02205 02206 int found = 0; 02207 02208 for (k = 0; k < nrow - 1; k++) { 02209 if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) { 02210 found = 1; 02211 break; 02212 } 02213 } 02214 02215 if (found) { 02216 correct[j] = (theta [k + 1] - theta [k]) / 02217 (lambda[k + 1] - lambda[k]) * 02218 (c_wave - lambda[k]) + theta[k]; 02219 correct[j] *= M_PI / 180; /* Radians */ 02220 } 02221 else if (j) 02222 correct[j] = correct[j-1]; 02223 else 02224 correct[j] = 0.0; 02225 02226 } 02227 02228 cpl_table_delete(chrotbl); 02229 } 02230 02231 for (j = 0; j < nobjects; j++) { 02232 double * ip_q, * ip_u, * ip_l, 02233 * ip_qnull, * ip_unull, * ipqerr, * ipuerr, * iplerr, 02234 * ipang, * ipangerr; 02235 02236 float * data; 02237 float * iffq, * ierrq, * iffu, * ierru; 02238 02239 int pos, pos_d; 02240 02241 ip_q = p_q + (nobjects - 1 - j) * nx; 02242 ip_u = p_u + (nobjects - 1 - j) * nx; 02243 ip_l = p_l + (nobjects - 1 - j) * nx; 02244 02245 if (nscience / 4 > 1) { 02246 ip_qnull = p_qnull + (nobjects - 1 - j) * nx; 02247 ip_unull = p_unull + (nobjects - 1 - j) * nx; 02248 } 02249 02250 ipqerr = pqerr + (nobjects - 1 - j) * nx; 02251 ipuerr = puerr + (nobjects - 1 - j) * nx; 02252 iplerr = plerr + (nobjects - 1 - j) * nx; 02253 02254 ipang = pang + (nobjects - 1 - j) * nx; 02255 ipangerr = pangerr + (nobjects - 1 - j) * nx; 02256 02257 while (total < j + 1) { 02258 p++; 02259 total += nobjs_per_slit[p]; 02260 } 02261 02262 for (k = 0; k < nscience / 4; k++) { 02263 float * if_o, * if_e, * ifdelta_o, * ifdelta_e; 02264 02265 /* First P_Q */ 02266 02267 pos = fors_find_angle_pos(angles, nscience, 90 * k); 02268 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45); 02269 02270 data = cpl_image_get_data_float(reduceds[pos]); 02271 02272 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02273 + (total - j - 1)) * nx; 02274 02275 if_e = data + (2 * (nobjects - total) 02276 + (total - j - 1)) * nx; 02277 02278 // if_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 02279 // if_e = data + 2 * (nobjects - 1 - j) * nx; 02280 02281 data = cpl_image_get_data_float(reduceds[pos_d]); 02282 02283 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02284 + (total - j - 1)) * nx; 02285 02286 ifdelta_e = data + (2 * (nobjects - total) 02287 + (total - j - 1)) * nx; 02288 02289 // ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 02290 // ifdelta_e = data + 2 * (nobjects - 1 - j) * nx; 02291 02292 for (m = 0; m < nx; m++) { 02293 02294 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 : 02295 (if_o[m] - if_e[m] ) / 02296 (if_o[m] + if_e[m] ) - 02297 (ifdelta_o[m] - ifdelta_e[m]) / 02298 (ifdelta_o[m] + ifdelta_e[m]); 02299 02300 quantity = isfinite(quantity) ? quantity : 0.0; 02301 02302 /* PQ map computation */ 02303 ip_q[m] += quantity * 0.5 / (nscience / 4); 02304 02305 /* PQnull map computation */ 02306 if (nscience / 4 > 1) { 02307 if (k % 2) 02308 ip_qnull[m] += quantity * 0.5 / (nscience / 4); 02309 else 02310 ip_qnull[m] -= quantity * 0.5 / (nscience / 4); 02311 } 02312 } 02313 02314 /* Now P_U */ 02315 02316 pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5); 02317 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5); 02318 02319 data = cpl_image_get_data_float(reduceds[pos]); 02320 02321 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02322 + (total - j - 1)) * nx; 02323 02324 if_e = data + (2 * (nobjects - total) 02325 + (total - j - 1)) * nx; 02326 02327 // if_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 02328 // if_e = data + 2 * (nobjects - 1 - j) * nx; 02329 02330 data = cpl_image_get_data_float(reduceds[pos_d]); 02331 02332 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02333 + (total - j - 1)) * nx; 02334 02335 ifdelta_e = data + (2 * (nobjects - total) 02336 + (total - j - 1)) * nx; 02337 02338 // ifdelta_o = data + (2 * (nobjects - 1 - j) + 1) * nx; 02339 // ifdelta_e = data + 2 * (nobjects - 1 - j) * nx; 02340 02341 for (m = 0; m < nx; m++) { 02342 02343 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 : 02344 (if_o[m] - if_e[m] ) / 02345 (if_o[m] + if_e[m] ) - 02346 (ifdelta_o[m] - ifdelta_e[m]) / 02347 (ifdelta_o[m] + ifdelta_e[m]); 02348 02349 quantity = isfinite(quantity) ? quantity : 0.0; 02350 02351 /* PU map computation */ 02352 ip_u[m] += quantity * 0.5 / (nscience / 4); 02353 02354 /* PUnull map computation */ 02355 if (nscience / 4 > 1) { 02356 if (k % 2) 02357 ip_unull[m] += quantity * 0.5 / (nscience / 4); 02358 else 02359 ip_unull[m] -= quantity * 0.5 / (nscience / 4); 02360 } 02361 } 02362 } 02363 02364 /* Error map */ 02365 02366 pos = fors_find_angle_pos(angles, nscience, 0.0); 02367 02368 data = cpl_image_get_data_float(reduceds[pos]); 02369 iffq = data + 2 * (nobjects - 1 - j) * nx; 02370 02371 data = cpl_image_get_data_float(rerrors[pos]); 02372 ierrq = data + 2 * (nobjects - 1 - j) * nx; 02373 02374 pos = fors_find_angle_pos(angles, nscience, 22.5); 02375 02376 data = cpl_image_get_data_float(reduceds[pos]); 02377 iffu = data + 2 * (nobjects - 1 - j) * nx; 02378 02379 data = cpl_image_get_data_float(rerrors[pos]); 02380 ierru = data + 2 * (nobjects - 1 - j) * nx; 02381 02382 for (m = 0; m < nx; m++) { 02383 02384 double radicand; 02385 02386 ipqerr[m] = iffq[m] <= 0.0 ? 02387 0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4); 02388 02389 ipuerr[m] = iffu[m] <= 0.0 ? 02390 0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4); 02391 02392 iplerr[m] = CPL_MATH_SQRT1_2 * 0.5 * (ipqerr[m] + ipuerr[m]); 02393 02394 /* Added: */ 02395 if (chromatism) { 02396 ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 02397 ip_u[m] * sin(2 * correct[m]); 02398 02399 ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 02400 ip_u[m] * cos(2 * correct[m]); 02401 } 02402 /* End added */ 02403 02404 /* PL computation */ 02405 ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]); 02406 02407 /* P angle computation */ 02408 ipang[m] = (ip_q[m] == 0.0 ? 02409 (ip_u[m] > 0.0 ? 45.0 : 135.0) 02410 : 0.5 * (atan2(ip_u[m], ip_q[m]) * 180 / M_PI + 02411 ((atan2(ip_u[m], ip_q[m]) > 0.0 ? 0.0 : 360.0)))); 02412 02413 /* Error on the angle computation */ 02414 radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] + 02415 ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m]; 02416 02417 ipangerr[m] = ip_l[m] == 0.0 ? 0.0 : 02418 sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI; 02419 02420 /* 02421 * Note: no need to apply chromatism correction to angle, 02422 * it is implicit in Q and U correction applied before. 02423 */ 02424 02425 /* Removed: 02426 if (chromatism) { 02427 ipang[m] -= correct[m]; 02428 02429 ip_q[m] = ip_q[m] * cos(2 * correct[m]) - 02430 ip_u[m] * sin(2 * correct[m]); 02431 02432 ip_u[m] = ip_q[m] * sin(2 * correct[m]) + 02433 ip_u[m] * cos(2 * correct[m]); 02434 02435 } 02436 end removed */ 02437 } 02438 02439 if (nscience / 4 > 1) { 02440 float * weights; 02441 float max, sum, sum2, imean; 02442 02443 int k; 02444 02445 /* QC on U NULL */ 02446 weights = cpl_malloc(sizeof(float) * nx); 02447 02448 max = 0.0; 02449 for (k = 0; k < nx; k++) { 02450 if (max < iffq[k]) max = iffq[k]; 02451 } 02452 02453 for (k = 0; k < nx; k++) { 02454 weights[k] = iffq[k] < 0.0 ? 02455 0.0 : iffq[k] * iffq[k] / (max * max); 02456 } 02457 02458 sum = 0.0; 02459 sum2 = 0.0; 02460 for (k = 0; k < nx; k++) { 02461 sum += weights[k] * ip_qnull[k]; 02462 sum2 += weights[k]; 02463 } 02464 02465 cpl_free(weights); 02466 02467 imean = sum / sum2; 02468 02469 mean_qnull += (imean - mean_qnull) / (j + 1.0); 02470 02471 /* QC on U NULL */ 02472 weights = cpl_malloc(sizeof(float) * nx); 02473 02474 max = 0.0; 02475 for (k = 0; k < nx; k++) { 02476 if (max < iffu[k]) max = iffu[k]; 02477 } 02478 02479 for (k = 0; k < nx; k++) { 02480 weights[k] = iffu[k] < 0.0 ? 02481 0.0 : iffu[k] * iffu[k] / (max * max); 02482 } 02483 02484 sum = 0.0; 02485 sum2 = 0.0; 02486 for (k = 0; k < nx; k++) { 02487 sum += weights[k] * ip_unull[k]; 02488 sum2 += weights[k]; 02489 } 02490 02491 cpl_free(weights); 02492 02493 imean = sum / sum2; 02494 02495 mean_unull += (imean - mean_unull) / (j + 1.0); 02496 } 02497 } 02498 02499 cpl_image_delete(correct_im); 02500 02501 if (dfs_save_image(frameset, pq_im, reduced_q_tag, header, 02502 parlist, recipe, version)) 02503 fors_pmos_extract_exit(NULL); 02504 02505 if (dfs_save_image(frameset, pu_im, reduced_u_tag, header, 02506 parlist, recipe, version)) 02507 fors_pmos_extract_exit(NULL); 02508 02509 if (dfs_save_image(frameset, pl_im, reduced_l_tag, header, 02510 parlist, recipe, version)) 02511 fors_pmos_extract_exit(NULL); 02512 02513 if (nscience / 4 > 1) { 02514 char *pipefile; 02515 char *keyname; 02516 cpl_propertylist *qheader = dfs_load_header(frameset, 02517 science_tag, 0); 02518 02519 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 02520 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 02521 cpl_propertylist_update_double(qheader, "CRVAL1", 02522 startwavelength + dispersion/2); 02523 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 02524 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02525 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02526 cpl_propertylist_update_double(qheader, "CD1_1", dispersion); 02527 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 02528 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 02529 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 02530 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 02531 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 02532 02533 fors_qc_start_group(qheader, "2.0", instrume); 02534 02535 /* 02536 * QC1 group header 02537 */ 02538 02539 if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag, 02540 "Product category", instrume)) 02541 fors_pmos_extract_exit("Cannot write product category to " 02542 "QC log file"); 02543 02544 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 02545 "DPR type", instrume)) 02546 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc " 02547 "lamp header"); 02548 02549 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 02550 "Template", instrume)) 02551 fors_pmos_extract_exit("Missing keyword TPL ID in arc " 02552 "lamp header"); 02553 02554 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 02555 "Grism name", instrume)) 02556 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc " 02557 "lamp header"); 02558 02559 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 02560 "Grism identifier", instrume)) 02561 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc " 02562 "lamp header"); 02563 02564 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 02565 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 02566 "Filter name", instrume); 02567 02568 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 02569 "Collimator name", instrume)) 02570 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc " 02571 "lamp header"); 02572 02573 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 02574 "Chip identifier", instrume)) 02575 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc " 02576 "lamp header"); 02577 02578 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 02579 "Archive name of input data", 02580 instrume)) 02581 fors_pmos_extract_exit("Missing keyword ARCFILE in arc " 02582 "lamp header"); 02583 02584 pipefile = dfs_generate_filename_tfits(reduced_nul_q_tag); 02585 if (fors_qc_write_string("PIPEFILE", pipefile, 02586 "Pipeline product name", instrume)) 02587 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file"); 02588 cpl_free(pipefile); pipefile = NULL; 02589 02590 02591 /* 02592 * QC1 parameters 02593 */ 02594 02595 keyname = "QC.NULL.Q.MEAN"; 02596 02597 if (fors_qc_write_qc_double(qheader, mean_qnull, 02598 keyname, NULL, 02599 "Mean Q null parameter", 02600 instrume)) { 02601 fors_pmos_extract_exit("Cannot write mean Q null parameter " 02602 "to QC log file"); 02603 } 02604 02605 fors_qc_end_group(); 02606 02607 if (dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader, 02608 parlist, recipe, version)) 02609 fors_pmos_extract_exit(NULL); 02610 02611 cpl_propertylist_delete(qheader); 02612 02613 qheader = dfs_load_header(frameset, science_tag, 0); 02614 02615 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 02616 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 02617 cpl_propertylist_update_double(qheader, "CRVAL1", 02618 startwavelength + dispersion/2); 02619 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 02620 /* cpl_propertylist_update_double(header, "CDELT1", dispersion); 02621 cpl_propertylist_update_double(header, "CDELT2", 1.0); */ 02622 cpl_propertylist_update_double(qheader, "CD1_1", dispersion); 02623 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 02624 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 02625 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 02626 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 02627 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 02628 02629 fors_qc_start_group(qheader, "2.0", instrume); 02630 02631 /* 02632 * QC1 group header 02633 */ 02634 02635 if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag, 02636 "Product category", instrume)) 02637 fors_pmos_extract_exit("Cannot write product category to " 02638 "QC log file"); 02639 02640 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 02641 "DPR type", instrume)) 02642 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc " 02643 "lamp header"); 02644 02645 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 02646 "Template", instrume)) 02647 fors_pmos_extract_exit("Missing keyword TPL ID in arc " 02648 "lamp header"); 02649 02650 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 02651 "Grism name", instrume)) 02652 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc " 02653 "lamp header"); 02654 02655 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 02656 "Grism identifier", instrume)) 02657 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc " 02658 "lamp header"); 02659 02660 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 02661 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 02662 "Filter name", instrume); 02663 02664 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 02665 "Collimator name", instrume)) 02666 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc " 02667 "lamp header"); 02668 02669 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 02670 "Chip identifier", instrume)) 02671 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc " 02672 "lamp header"); 02673 02674 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 02675 "Archive name of input data", 02676 instrume)) 02677 fors_pmos_extract_exit("Missing keyword ARCFILE in arc " 02678 "lamp header"); 02679 02680 pipefile = dfs_generate_filename_tfits(reduced_nul_u_tag); 02681 if (fors_qc_write_string("PIPEFILE", pipefile, 02682 "Pipeline product name", instrume)) 02683 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file"); 02684 cpl_free(pipefile); pipefile = NULL; 02685 02686 02687 /* 02688 * QC1 parameters 02689 */ 02690 02691 keyname = "QC.NULL.U.MEAN"; 02692 02693 if (fors_qc_write_qc_double(qheader, mean_unull, 02694 keyname, NULL, 02695 "Mean U null parameter", 02696 instrume)) { 02697 fors_pmos_extract_exit("Cannot write mean U null parameter " 02698 "to QC log file"); 02699 } 02700 02701 fors_qc_end_group(); 02702 02703 if (dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader, 02704 parlist, recipe, version)) 02705 fors_pmos_extract_exit(NULL); 02706 02707 cpl_propertylist_delete(qheader); 02708 } 02709 02710 if (dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header, 02711 parlist, recipe, version)) 02712 fors_pmos_extract_exit(NULL); 02713 02714 if (dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header, 02715 parlist, recipe, version)) 02716 fors_pmos_extract_exit(NULL); 02717 02718 if (dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header, 02719 parlist, recipe, version)) 02720 fors_pmos_extract_exit(NULL); 02721 02722 if (dfs_save_image(frameset, pang_im, reduced_angle_tag, header, 02723 parlist, recipe, version)) 02724 fors_pmos_extract_exit(NULL); 02725 02726 if (dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag, 02727 header, parlist, recipe, version)) 02728 fors_pmos_extract_exit(NULL); 02729 02730 cpl_image_delete(pq_im); 02731 cpl_image_delete(pu_im); 02732 cpl_image_delete(pl_im); 02733 02734 cpl_image_delete(pqnull_im); 02735 cpl_image_delete(punull_im); 02736 02737 cpl_image_delete(pqerr_im); 02738 cpl_image_delete(puerr_im); 02739 cpl_image_delete(plerr_im); 02740 cpl_image_delete(pang_im); 02741 cpl_image_delete(pangerr_im); 02742 } 02743 02744 cpl_propertylist_delete(header); 02745 02746 /* End of Stokes computation */ 02747 02748 for (j = 0; j < nscience; j++) { 02749 cpl_image_delete(reduceds[j]); 02750 cpl_image_delete(rerrors[j]); 02751 cpl_table_delete(slitss[j]); 02752 cpl_image_delete(mappeds[j]); 02753 } 02754 02755 cpl_free(reduceds); 02756 cpl_free(rerrors); 02757 cpl_free(slitss); 02758 cpl_free(mappeds); 02759 02760 cpl_free(instrume); instrume = NULL; 02761 02762 cpl_free(skylocalmaps); 02763 cpl_free(nobjs_per_slit); 02764 02765 if (cpl_error_get_code()) { 02766 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 02767 fors_pmos_extract_exit(NULL); 02768 } 02769 else 02770 return 0; 02771 } 02772 02773 /*----------------------------------------------------------------------------*/ 02784 /*----------------------------------------------------------------------------*/ 02785 static float * fors_check_angles(cpl_frameset * frameset, 02786 int pmos, const char *tag, int * circ) 02787 { 02788 float *angles = NULL; 02789 cpl_frame *c_frame = NULL; 02790 char *ret_id = NULL; 02791 02792 int i = 0; 02793 02794 angles = cpl_malloc(sizeof(float) * pmos); 02795 02796 for (c_frame = cpl_frameset_find(frameset, tag); 02797 c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) { 02798 02799 cpl_propertylist * header = 02800 cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0); 02801 02802 if (!ret_id) { 02803 ret_id = cpl_strdup(cpl_propertylist_get_string(header, 02804 "ESO INS OPTI4 ID")); 02805 02806 if (ret_id[1] != '5' && ret_id[1] != '4') { 02807 cpl_msg_error(cpl_func, 02808 "Unknown retarder plate id: %s", ret_id); 02809 return NULL; 02810 } 02811 } else { 02812 char * c_ret_id = (char *) 02813 cpl_propertylist_get_string(header, "ESO INS OPTI4 ID"); 02814 if (ret_id[1] != c_ret_id[1]) { 02815 cpl_msg_error(cpl_func, "Input frames are not from the same " 02816 "retarder plate"); 02817 return NULL; 02818 } 02819 } 02820 02821 if (ret_id[1] == '5') { /* Linear polarimetry */ 02822 angles[i] = (float) 02823 cpl_propertylist_get_double(header, "ESO INS RETA2 ROT"); 02824 *circ = 0; 02825 } else { /* Circular polarimetry */ 02826 angles[i] = (float) 02827 cpl_propertylist_get_double(header, "ESO INS RETA4 ROT"); 02828 *circ = 1; 02829 } 02830 02831 cpl_propertylist_delete(header); 02832 i++; 02833 } 02834 02835 cpl_free(ret_id); 02836 02837 if (*circ) { 02838 if (pmos != 2 && pmos != 4) { 02839 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles " 02840 "found, but either 2 or 4 are required for " 02841 "circular polarization measurements!", pmos); 02842 return NULL; 02843 } 02844 } else { 02845 if (pmos != 4 && pmos != 8 && pmos != 16) { 02846 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles " 02847 "found, but either 4, 8, or 16 are required for " 02848 "linear polarization measurements!", pmos); 02849 return NULL; 02850 } 02851 } 02852 02853 /* Check completeness */ 02854 02855 if (*circ) { 02856 for (i = 0; i < pmos; i++) { 02857 if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) { 02858 const char *cangles; 02859 switch (pmos) { 02860 case 2: cangles = "-45.0, 45.0"; break; 02861 case 4: cangles = "-45.0, 45.0, 135.0, 225.0"; break; 02862 default: assert(0); 02863 } 02864 02865 cpl_msg_error(cpl_func, "Wrong angle configuration: missing " 02866 "angle %.2f. All angles %s must be provided.", 02867 angles[i], cangles); 02868 return NULL; 02869 } 02870 } 02871 } 02872 else { 02873 for (i = 0; i < pmos; i++) { 02874 if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) { 02875 const char *cangles; 02876 switch (pmos) { 02877 case 4: cangles = "0.0, 22.5, 45.0, 67.5"; break; 02878 case 8: cangles = "0.0, 22.5, 45.0, 67.5, " 02879 "90.0, 112.5, 135.0, 157.5"; break; 02880 case 16: cangles = "0.0, 22.5, 45.0, 67.5, " 02881 "90.0, 112.5, 135.0, 157.5, " 02882 "180.0, 202.5, 225.0, 247.5, " 02883 "270.0, 292.5, 315.0, 337.5"; break; 02884 default: assert(0); 02885 } 02886 02887 cpl_msg_error(cpl_func, "Wrong angle configuration: missing " 02888 "angle %.2f. All angles %s must be provided.", 02889 angles[i], cangles); 02890 return NULL; 02891 } 02892 } 02893 } 02894 02895 return angles; 02896 } 02897 02898 /*----------------------------------------------------------------------------*/ 02906 /*----------------------------------------------------------------------------*/ 02907 static int 02908 fors_find_angle_pos(float * angles, int nangles, float angle) 02909 { 02910 int i, match = 0; 02911 02912 for (i = 0; i < nangles; i++) { 02913 if (fabs(angles[i] - angle) < 1.0 || 02914 fabs(angles[i] - 360.0 - angle) < 1.0) { 02915 match = 1; 02916 break; 02917 } 02918 } 02919 02920 return match ? i : -1; 02921 }