FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_pmos_science.c,v 1.63 2013/02/28 15:15:40 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:40 $ 00024 * $Revision: 1.63 $ 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_science_create(cpl_plugin *); 00044 static int fors_pmos_science_exec(cpl_plugin *); 00045 static int fors_pmos_science_destroy(cpl_plugin *); 00046 static int fors_pmos_science(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_science_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 " MASTER_NORM_FLAT_PMOS Calib Normalised flat field .\n" 00084 " DISP_COEFF_PMOS Calib Inverse dispersion Y\n" 00085 " CURV_COEFF_PMOS Calib Spectral curvature Y\n" 00086 " SLIT_LOCATION_PMOS Calib Slits positions table Y\n" 00087 " RETARDER_WAVEPLATE_CHROMATISM Calib Chromatism correction .\n" 00088 " STD_PMOS_TABLE Calib Linear pol. of std stars .\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_X_SCI_PMOS FITS image X Stokes parameter (and L)\n" 00096 " REDUCED_ERROR_X_SCI_PMOS FITS image Error on X Stokes parameter\n" 00097 " REDUCED_NUL_X_SCI_PMOS FITS image Null parameter for X\n" 00098 " REDUCED_ANGLE_SCI_PMOS FITS image Direction of linear polarization\n" 00099 " REDUCED_ERROR_ANGLE_SCI_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 " OBJECT_TABLE_SCI_PMOS FITS table Positions of detected objects\n" 00106 " OBJECT_TABLE_POL_SCI_PMOS FITS table Positions of real objects\n" 00107 "\n" 00108 " Only if the sky-alignment of the wavelength solution is requested:\n" 00109 " DISP_COEFF_SCI_PMOS FITS table Upgraded dispersion coefficients\n" 00110 " WAVELENGTH_MAP_SCI_PMOS FITS image Upgraded wavelength map\n\n"; 00111 00112 #define fors_pmos_science_exit(message) \ 00113 { \ 00114 if (message) cpl_msg_error(recipe, message); \ 00115 cpl_free(instrume); \ 00116 cpl_image_delete(dummy); \ 00117 cpl_image_delete(mapped_sky); \ 00118 cpl_image_delete(mapped_cleaned); \ 00119 cpl_image_delete(skymap); \ 00120 cpl_image_delete(smapped); \ 00121 cpl_table_delete(offsets); \ 00122 cpl_table_delete(sky); \ 00123 cpl_image_delete(bias); \ 00124 cpl_image_delete(spectra); \ 00125 cpl_image_delete(coordinate); \ 00126 cpl_image_delete(norm_flat); \ 00127 cpl_image_delete(rainbow); \ 00128 cpl_image_delete(rectified); \ 00129 cpl_image_delete(wavemap); \ 00130 cpl_propertylist_delete(header); \ 00131 cpl_propertylist_delete(save_header); \ 00132 cpl_table_delete(grism_table); \ 00133 cpl_table_delete(idscoeff); \ 00134 cpl_table_delete(maskslits); \ 00135 cpl_table_delete(overscans); \ 00136 cpl_table_delete(polytraces); \ 00137 cpl_table_delete(wavelengths); \ 00138 cpl_table_delete(mask_science); \ 00139 cpl_table_delete(mask_arc); \ 00140 cpl_table_delete(mask_flat); \ 00141 cpl_vector_delete(lines); \ 00142 cpl_msg_indent_less(); \ 00143 return -1; \ 00144 } 00145 00146 00147 #define fors_pmos_science_exit_memcheck(message) \ 00148 { \ 00149 if (message) cpl_msg_info(recipe, message); \ 00150 cpl_free(instrume); \ 00151 cpl_image_delete(dummy); \ 00152 cpl_image_delete(mapped_cleaned); \ 00153 cpl_image_delete(mapped_sky); \ 00154 cpl_image_delete(skymap); \ 00155 cpl_image_delete(smapped); \ 00156 cpl_table_delete(offsets); \ 00157 cpl_table_delete(sky); \ 00158 cpl_image_delete(bias); \ 00159 cpl_image_delete(spectra); \ 00160 cpl_image_delete(coordinate); \ 00161 cpl_image_delete(norm_flat); \ 00162 cpl_image_delete(rainbow); \ 00163 cpl_image_delete(rectified); \ 00164 cpl_image_delete(wavemap); \ 00165 cpl_propertylist_delete(header); \ 00166 cpl_propertylist_delete(save_header); \ 00167 cpl_table_delete(grism_table); \ 00168 cpl_table_delete(idscoeff); \ 00169 cpl_table_delete(maskslits); \ 00170 cpl_table_delete(overscans); \ 00171 cpl_table_delete(polytraces); \ 00172 cpl_table_delete(wavelengths); \ 00173 cpl_table_delete(mask_science); \ 00174 cpl_table_delete(mask_arc); \ 00175 cpl_table_delete(mask_flat); \ 00176 cpl_vector_delete(lines); \ 00177 cpl_msg_indent_less(); \ 00178 return 0; \ 00179 } 00180 00181 00193 int cpl_plugin_get_info(cpl_pluginlist *list) 00194 { 00195 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00196 cpl_plugin *plugin = &recipe->interface; 00197 00198 cpl_plugin_init(plugin, 00199 CPL_PLUGIN_API, 00200 FORS_BINARY_VERSION, 00201 CPL_PLUGIN_TYPE_RECIPE, 00202 "fors_pmos_science", 00203 "Extraction of scientific spectra", 00204 fors_pmos_science_description, 00205 "Carlo Izzo", 00206 PACKAGE_BUGREPORT, 00207 "This file is currently part of the FORS Instrument Pipeline\n" 00208 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00209 "This program is free software; you can redistribute it and/or modify\n" 00210 "it under the terms of the GNU General Public License as published by\n" 00211 "the Free Software Foundation; either version 2 of the License, or\n" 00212 "(at your option) any later version.\n\n" 00213 "This program is distributed in the hope that it will be useful,\n" 00214 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00215 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00216 "GNU General Public License for more details.\n\n" 00217 "You should have received a copy of the GNU General Public License\n" 00218 "along with this program; if not, write to the Free Software Foundation,\n" 00219 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00220 fors_pmos_science_create, 00221 fors_pmos_science_exec, 00222 fors_pmos_science_destroy); 00223 00224 cpl_pluginlist_append(list, plugin); 00225 00226 return 0; 00227 } 00228 00229 00240 static int fors_pmos_science_create(cpl_plugin *plugin) 00241 { 00242 cpl_recipe *recipe; 00243 cpl_parameter *p; 00244 00245 00246 /* 00247 * Check that the plugin is part of a valid recipe 00248 */ 00249 00250 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00251 recipe = (cpl_recipe *)plugin; 00252 else 00253 return -1; 00254 00255 /* 00256 * Create the parameters list in the cpl_recipe object 00257 */ 00258 00259 recipe->parameters = cpl_parameterlist_new(); 00260 00261 00262 /* 00263 * Dispersion 00264 */ 00265 00266 p = cpl_parameter_new_value("fors.fors_pmos_science.dispersion", 00267 CPL_TYPE_DOUBLE, 00268 "Expected spectral dispersion (Angstrom/pixel)", 00269 "fors.fors_pmos_science", 00270 0.0); 00271 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00272 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00273 cpl_parameterlist_append(recipe->parameters, p); 00274 00275 /* 00276 * Rebin 00277 */ 00278 00279 p = cpl_parameter_new_value("fors.fors_pmos_science.rebin", 00280 CPL_TYPE_INT, 00281 "Rebin (pixel)", 00282 "fors.fors_pmos_science", 00283 1); 00284 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rebin"); 00285 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00286 cpl_parameterlist_append(recipe->parameters, p); 00287 00288 /* 00289 * Sky lines alignment 00290 */ 00291 00292 p = cpl_parameter_new_value("fors.fors_pmos_science.skyalign", 00293 CPL_TYPE_INT, 00294 "Polynomial order for sky lines alignment, " 00295 "or -1 to avoid alignment", 00296 "fors.fors_pmos_science", 00297 0); 00298 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign"); 00299 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00300 cpl_parameterlist_append(recipe->parameters, p); 00301 00302 /* 00303 * Line catalog table column containing the sky reference wavelengths 00304 */ 00305 00306 p = cpl_parameter_new_value("fors.fors_pmos_science.wcolumn", 00307 CPL_TYPE_STRING, 00308 "Name of sky line catalog table column " 00309 "with wavelengths", 00310 "fors.fors_pmos_science", 00311 "WLEN"); 00312 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn"); 00313 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00314 cpl_parameterlist_append(recipe->parameters, p); 00315 00316 /* 00317 * Start wavelength for spectral extraction 00318 */ 00319 00320 p = cpl_parameter_new_value("fors.fors_pmos_science.startwavelength", 00321 CPL_TYPE_DOUBLE, 00322 "Start wavelength in spectral extraction", 00323 "fors.fors_pmos_science", 00324 0.0); 00325 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00326 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00327 cpl_parameterlist_append(recipe->parameters, p); 00328 00329 /* 00330 * End wavelength for spectral extraction 00331 */ 00332 00333 p = cpl_parameter_new_value("fors.fors_pmos_science.endwavelength", 00334 CPL_TYPE_DOUBLE, 00335 "End wavelength in spectral extraction", 00336 "fors.fors_pmos_science", 00337 0.0); 00338 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00339 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00340 cpl_parameterlist_append(recipe->parameters, p); 00341 00342 /* 00343 * Flux conservation 00344 */ 00345 00346 p = cpl_parameter_new_value("fors.fors_pmos_science.flux", 00347 CPL_TYPE_BOOL, 00348 "Apply flux conservation", 00349 "fors.fors_pmos_science", 00350 TRUE); 00351 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux"); 00352 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00353 cpl_parameterlist_append(recipe->parameters, p); 00354 00355 /* 00356 * Apply flat field 00357 */ 00358 00359 p = cpl_parameter_new_value("fors.fors_pmos_science.flatfield", 00360 CPL_TYPE_BOOL, 00361 "Apply flat field", 00362 "fors.fors_pmos_science", 00363 TRUE); 00364 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield"); 00365 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00366 cpl_parameterlist_append(recipe->parameters, p); 00367 00368 /* 00369 * Median sky subtraction method 00370 */ 00371 00372 p = cpl_parameter_new_value("fors.fors_pmos_science.skymedian", 00373 CPL_TYPE_BOOL, 00374 "Sky subtraction from extracted slit spectra", 00375 "fors.fors_pmos_science", 00376 FALSE); 00377 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian"); 00378 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00379 cpl_parameterlist_append(recipe->parameters, p); 00380 00381 /* 00382 * Local sky subtraction on CCD spectra 00383 */ 00384 00385 p = cpl_parameter_new_value("fors.fors_pmos_science.skylocal", 00386 CPL_TYPE_BOOL, 00387 "Sky subtraction from CCD slit spectra", 00388 "fors.fors_pmos_science", 00389 TRUE); 00390 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal"); 00391 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00392 cpl_parameterlist_append(recipe->parameters, p); 00393 00394 /* 00395 * Cosmic rays removal 00396 */ 00397 00398 p = cpl_parameter_new_value("fors.fors_pmos_science.cosmics", 00399 CPL_TYPE_BOOL, 00400 "Eliminate cosmic rays hits (only if local " 00401 "sky subtraction is also requested)", 00402 "fors.fors_pmos_science", 00403 FALSE); 00404 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics"); 00405 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00406 cpl_parameterlist_append(recipe->parameters, p); 00407 00408 /* 00409 * Slit margin 00410 */ 00411 00412 p = cpl_parameter_new_value("fors.fors_pmos_science.slit_margin", 00413 CPL_TYPE_INT, 00414 "Number of pixels to exclude at each slit " 00415 "in object detection and extraction", 00416 "fors.fors_pmos_science", 00417 3); 00418 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin"); 00419 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00420 cpl_parameterlist_append(recipe->parameters, p); 00421 00422 /* 00423 * Extraction radius 00424 */ 00425 00426 p = cpl_parameter_new_value("fors.fors_pmos_science.ext_radius", 00427 CPL_TYPE_INT, 00428 "Maximum extraction radius for detected " 00429 "objects (pixel)", 00430 "fors.fors_pmos_science", 00431 12); 00432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius"); 00433 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00434 cpl_parameterlist_append(recipe->parameters, p); 00435 00436 /* 00437 * Contamination radius 00438 */ 00439 00440 p = cpl_parameter_new_value("fors.fors_pmos_science.cont_radius", 00441 CPL_TYPE_INT, 00442 "Minimum distance at which two objects " 00443 "of equal luminosity do not contaminate " 00444 "each other (pixel)", 00445 "fors.fors_pmos_science", 00446 0); 00447 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius"); 00448 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00449 cpl_parameterlist_append(recipe->parameters, p); 00450 00451 /* 00452 * Object extraction method 00453 */ 00454 00455 p = cpl_parameter_new_value("fors.fors_pmos_science.ext_mode", 00456 CPL_TYPE_INT, 00457 "Object extraction method: 0 = aperture, " 00458 "1 = Horne optimal extraction", 00459 "fors.fors_pmos_science", 00460 1); 00461 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode"); 00462 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00463 cpl_parameterlist_append(recipe->parameters, p); 00464 00465 /* 00466 * Tolerance in object matching 00467 */ 00468 00469 p = cpl_parameter_new_value("fors.fors_pmos_science.match_tolerance", 00470 CPL_TYPE_DOUBLE, 00471 "Tolerance for matching spectra from the " 00472 "same object at different angles and beams " 00473 "(pixel)", 00474 "fors.fors_pmos_science", 00475 5.0); 00476 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "match_tolerance"); 00477 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00478 cpl_parameterlist_append(recipe->parameters, p); 00479 00480 /* 00481 * Normalise output by exposure time 00482 */ 00483 00484 p = cpl_parameter_new_value("fors.fors_pmos_science.time_normalise", 00485 CPL_TYPE_BOOL, 00486 "Normalise output spectra by the exposure time", 00487 "fors.fors_pmos_science", 00488 TRUE); 00489 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise"); 00490 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00491 cpl_parameterlist_append(recipe->parameters, p); 00492 00493 /* 00494 * Apply chromatism correction to polarization angle 00495 */ 00496 00497 p = cpl_parameter_new_value("fors.fors_pmos_science.chromatism", 00498 CPL_TYPE_BOOL, 00499 "Chromatism correction to polarization angles", 00500 "fors.fors_pmos_science", 00501 TRUE); 00502 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "chromatism"); 00503 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00504 cpl_parameterlist_append(recipe->parameters, p); 00505 00506 /* 00507 * Rotation correction for linear polarisation 00508 */ 00509 00510 p = cpl_parameter_new_value("fors.fors_pmos_science.wollaston", 00511 CPL_TYPE_BOOL, 00512 "Wollaston mounting (FORS2 only): true = 0 degrees " 00513 "(ord. beam on top, extr. beam on bottom), " 00514 "false = 180 degrees (beams are reversed), for FORS1 " 00515 "is frozen to true", 00516 "fors.fors_pmos_science", 00517 TRUE); 00518 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wollaston"); 00519 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00520 cpl_parameterlist_append(recipe->parameters, p); 00521 00522 /* 00523 * Create check products 00524 */ 00525 00526 p = cpl_parameter_new_value("fors.fors_pmos_science.check", 00527 CPL_TYPE_BOOL, 00528 "Create intermediate products", 00529 "fors.fors_pmos_science", 00530 FALSE); 00531 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "check"); 00532 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00533 cpl_parameterlist_append(recipe->parameters, p); 00534 00535 /* 00536 * Computation of QC1 parameters 00537 */ 00538 00539 p = cpl_parameter_new_value("fors.fors_pmos_science.qc", 00540 CPL_TYPE_BOOL, 00541 "Compute QC1 parameters", 00542 "fors.fors_pmos_science", 00543 TRUE); 00544 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc"); 00545 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00546 cpl_parameterlist_append(recipe->parameters, p); 00547 00548 return 0; 00549 } 00550 00551 00560 static int fors_pmos_science_exec(cpl_plugin *plugin) 00561 { 00562 cpl_recipe *recipe; 00563 00564 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00565 recipe = (cpl_recipe *)plugin; 00566 else 00567 return -1; 00568 00569 return fors_pmos_science(recipe->parameters, recipe->frames); 00570 } 00571 00572 00581 static int fors_pmos_science_destroy(cpl_plugin *plugin) 00582 { 00583 cpl_recipe *recipe; 00584 00585 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00586 recipe = (cpl_recipe *)plugin; 00587 else 00588 return -1; 00589 00590 cpl_parameterlist_delete(recipe->parameters); 00591 00592 return 0; 00593 } 00594 00595 00605 static int fors_pmos_science(cpl_parameterlist *parlist, cpl_frameset *frameset) 00606 { 00607 00608 const char *recipe = "fors_pmos_science"; 00609 00610 00611 /* 00612 * Input parameters 00613 */ 00614 00615 double dispersion; 00616 int group; 00617 int skyalign; 00618 const char *wcolumn; 00619 double startwavelength; 00620 double endwavelength; 00621 int flux; 00622 int flatfield; 00623 int skylocal; 00624 int skymedian; 00625 int chromatism; 00626 double wollaston; 00627 int cosmics; 00628 int slit_margin; 00629 int ext_radius; 00630 int cont_radius; 00631 int ext_mode; 00632 double tolerance; 00633 int time_normalise; 00634 int check; 00635 int qc; 00636 00637 /* 00638 * CPL objects 00639 */ 00640 00641 cpl_image **images; 00642 00643 cpl_image **reduceds = NULL; 00644 cpl_image **rerrors = NULL; 00645 cpl_table **slitss = NULL; 00646 cpl_image **mappeds = NULL; 00647 cpl_image **skylocalmaps = NULL; 00648 00649 int nobjects = 0; 00650 00651 cpl_image *bias = NULL; 00652 cpl_image *norm_flat = NULL; 00653 cpl_image *spectra = NULL; 00654 cpl_image *rectified = NULL; 00655 cpl_image *coordinate = NULL; 00656 cpl_image *rainbow = NULL; 00657 cpl_image *mapped = NULL; 00658 cpl_image *mapped_sky = NULL; 00659 cpl_image *mapped_cleaned = NULL; 00660 cpl_image *smapped = NULL; 00661 cpl_image *wavemap = NULL; 00662 cpl_image *skymap = NULL; 00663 cpl_image *skylocalmap = NULL; 00664 cpl_image *dummy = NULL; 00665 00666 cpl_table *grism_table = NULL; 00667 cpl_table *overscans = NULL; 00668 cpl_table *wavelengths = NULL; 00669 cpl_table *idscoeff = NULL; 00670 cpl_table *slits = NULL; 00671 cpl_table *origslits = NULL; 00672 cpl_table *maskslits = NULL; 00673 cpl_table *mask_science = NULL; 00674 cpl_table *mask_arc = NULL; 00675 cpl_table *mask_flat = NULL; 00676 cpl_table *polytraces = NULL; 00677 cpl_table *offsets = NULL; 00678 cpl_table *sky = NULL; 00679 00680 cpl_vector *lines = NULL; 00681 00682 cpl_propertylist *header = NULL; 00683 cpl_propertylist *save_header = NULL; 00684 00685 /* 00686 * Auxiliary variables 00687 */ 00688 00689 char version[80]; 00690 char *instrume = NULL; 00691 const char *science_tag; 00692 const char *master_norm_flat_tag; 00693 const char *disp_coeff_tag; 00694 const char *disp_coeff_sky_tag; 00695 const char *wavelength_map_sky_tag; 00696 const char *curv_coeff_tag; 00697 const char *slit_location_tag; 00698 const char *reduced_science_tag; 00699 const char *reduced_sky_tag; 00700 const char *reduced_error_tag; 00701 const char *mapped_science_tag; 00702 const char *unmapped_science_tag; 00703 const char *mapped_science_sky_tag; 00704 const char *mapped_sky_tag; 00705 const char *unmapped_sky_tag; 00706 const char *object_table_tag; 00707 const char *object_table_pol_tag; 00708 const char *skylines_offsets_tag; 00709 const char *reduced_q_tag; 00710 const char *reduced_u_tag; 00711 const char *reduced_v_tag; 00712 const char *reduced_l_tag; 00713 const char *reduced_i_tag; 00714 const char *reduced_error_q_tag; 00715 const char *reduced_error_u_tag; 00716 const char *reduced_error_v_tag; 00717 const char *reduced_error_l_tag; 00718 const char *reduced_error_i_tag; 00719 const char *reduced_nul_q_tag; 00720 const char *reduced_nul_u_tag; 00721 const char *reduced_nul_v_tag; 00722 const char *reduced_angle_tag; 00723 const char *reduced_error_angle_tag; 00724 const char *chrom_table_tag = "RETARDER_WAVEPLATE_CHROMATISM"; 00725 const char *std_pmos_table_tag = "STD_PMOS_TABLE"; 00726 float *angles = NULL; 00727 int pmos, circ; 00728 int nscience; 00729 double alltime; 00730 double mean_rms; 00731 int nlines; 00732 int rebin; 00733 double *line; 00734 int nx = 0, ny; 00735 int ccd_xsize, ccd_ysize; 00736 double reference; 00737 double gain; 00738 double ron; 00739 double ra, dec; 00740 char filter; 00741 double qc_angle; 00742 double qc_angle_err; 00743 double qc_pl; 00744 double qc_pl_err; 00745 int standard; 00746 int polarised; 00747 int highres; 00748 int i, j; 00749 00750 int *nobjs_per_slit; 00751 int nslits; 00752 00753 int bagoo = 0; 00754 double blevel = 0.0; 00755 int doit = 0; // montecarlo simulation 00756 int conta = 0; // Bagoo, conta gli oggetti con S/N > s2n 00757 int bright = 0; // Bagoo, marca un oggetto con S/N > s2n 00758 int nslits_out_det = 0; 00759 00760 00761 cpl_error_code error; 00762 00763 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION); 00764 00765 if (bagoo) { 00766 char *montecarlo = getenv("MONTECARLO"); 00767 00768 if (montecarlo) { 00769 doit = atoi(montecarlo); 00770 } 00771 } 00772 00773 cpl_msg_set_indentation(2); 00774 00775 if (dfs_files_dont_exist(frameset)) 00776 fors_pmos_science_exit(NULL); 00777 00778 fors_dfs_set_groups(frameset); 00779 00780 00781 /* 00782 * Get configuration parameters 00783 */ 00784 00785 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00786 cpl_msg_indent_more(); 00787 00788 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00789 fors_pmos_science_exit("Too many in input: GRISM_TABLE"); 00790 00791 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00792 00793 dispersion = dfs_get_parameter_double(parlist, 00794 "fors.fors_pmos_science.dispersion", grism_table); 00795 00796 if (dispersion <= 0.0) 00797 fors_pmos_science_exit("Invalid spectral dispersion"); 00798 00799 group = dfs_get_parameter_int(parlist, 00800 "fors.fors_pmos_science.rebin", NULL); 00801 00802 if (group < 1) 00803 fors_pmos_science_exit("Invalid rebin factor"); 00804 00805 skyalign = dfs_get_parameter_int(parlist, 00806 "fors.fors_pmos_science.skyalign", NULL); 00807 00808 if (skyalign > 2) 00809 fors_pmos_science_exit("Max polynomial degree for sky alignment is 2"); 00810 00811 wcolumn = dfs_get_parameter_string(parlist, 00812 "fors.fors_pmos_science.wcolumn", NULL); 00813 00814 startwavelength = dfs_get_parameter_double(parlist, 00815 "fors.fors_pmos_science.startwavelength", grism_table); 00816 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00817 fors_pmos_science_exit("Invalid wavelength"); 00818 00819 endwavelength = dfs_get_parameter_double(parlist, 00820 "fors.fors_pmos_science.endwavelength", grism_table); 00821 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00822 fors_pmos_science_exit("Invalid wavelength"); 00823 00824 if (endwavelength - startwavelength <= 0.0) 00825 fors_pmos_science_exit("Invalid wavelength interval"); 00826 00827 flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_science.flux", NULL); 00828 00829 flatfield = dfs_get_parameter_bool(parlist, 00830 "fors.fors_pmos_science.flatfield", 00831 NULL); 00832 00833 skylocal = dfs_get_parameter_bool(parlist, 00834 "fors.fors_pmos_science.skylocal", 00835 NULL); 00836 skymedian = dfs_get_parameter_bool(parlist, 00837 "fors.fors_pmos_science.skymedian", 00838 NULL); 00839 00840 chromatism = dfs_get_parameter_bool(parlist, 00841 "fors.fors_pmos_science.chromatism", 00842 NULL); 00843 00844 wollaston = dfs_get_parameter_bool(parlist, 00845 "fors.fors_pmos_science.wollaston", 00846 NULL); 00847 00848 wollaston = wollaston ? 0 : 1; 00849 00850 if (skylocal && skymedian) 00851 fors_pmos_science_exit("Cannot apply sky subtraction both on " 00852 "extracted and non-extracted spectra"); 00853 00854 cosmics = dfs_get_parameter_bool(parlist, 00855 "fors.fors_pmos_science.cosmics", NULL); 00856 00857 if (cosmics) 00858 if (!skylocal) 00859 fors_pmos_science_exit("Cosmic rays correction requires " 00860 "skylocal=true"); 00861 00862 slit_margin = dfs_get_parameter_int(parlist, 00863 "fors.fors_pmos_science.slit_margin", 00864 NULL); 00865 if (slit_margin < 0) 00866 fors_pmos_science_exit("Value must be zero or positive"); 00867 00868 ext_radius = dfs_get_parameter_int(parlist, 00869 "fors.fors_pmos_science.ext_radius", 00870 NULL); 00871 if (ext_radius < 0) 00872 fors_pmos_science_exit("Value must be zero or positive"); 00873 00874 cont_radius = dfs_get_parameter_int(parlist, 00875 "fors.fors_pmos_science.cont_radius", 00876 NULL); 00877 if (cont_radius < 0) 00878 fors_pmos_science_exit("Value must be zero or positive"); 00879 00880 ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_science.ext_mode", 00881 NULL); 00882 if (ext_mode < 0 || ext_mode > 1) 00883 fors_pmos_science_exit("Invalid object extraction mode"); 00884 00885 tolerance = dfs_get_parameter_double(parlist, 00886 "fors.fors_pmos_science.match_tolerance", NULL); 00887 if (tolerance <= 0.0) 00888 fors_pmos_science_exit("Invalid object match tolerance"); 00889 00890 time_normalise = dfs_get_parameter_bool(parlist, 00891 "fors.fors_pmos_science.time_normalise", NULL); 00892 00893 check = dfs_get_parameter_bool(parlist, 00894 "fors.fors_pmos_science.check", NULL); 00895 00896 qc = dfs_get_parameter_bool(parlist, "fors.fors_pmos_science.qc", NULL); 00897 00898 cpl_table_delete(grism_table); grism_table = NULL; 00899 00900 if (cpl_error_get_code()) 00901 fors_pmos_science_exit("Failure getting the configuration parameters"); 00902 00903 00904 /* 00905 * Check input set-of-frames 00906 */ 00907 00908 cpl_msg_indent_less(); 00909 cpl_msg_info(recipe, "Check input set-of-frames:"); 00910 cpl_msg_indent_more(); 00911 00912 { 00913 cpl_frameset *subframeset = cpl_frameset_duplicate(frameset); 00914 cpl_frameset_erase(subframeset, "MASTER_BIAS"); 00915 00916 if (!dfs_equal_keyword(subframeset, "ESO INS GRIS1 ID")) 00917 fors_pmos_science_exit("Input frames are not from the same grism"); 00918 00919 if (!dfs_equal_keyword(subframeset, "ESO INS FILT1 ID")) 00920 fors_pmos_science_exit("Input frames are not from the same filter"); 00921 00922 if (!dfs_equal_keyword(subframeset, "ESO DET CHIP1 ID")) 00923 fors_pmos_science_exit("Input frames are not from the same chip"); 00924 00925 cpl_frameset_delete(subframeset); 00926 } 00927 00928 standard = 0; 00929 pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS"); 00930 00931 if (pmos == 0) { 00932 pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS"); 00933 standard = 1; 00934 } 00935 00936 if (pmos == 0) 00937 fors_pmos_science_exit("Missing input scientific frame"); 00938 00939 angles = fors_check_angles(frameset, pmos, 00940 standard ? "STANDARD_PMOS" : "SCIENCE_PMOS", 00941 &circ); 00942 if (angles == NULL) 00943 fors_pmos_science_exit("Polarization angles could not be read"); 00944 00945 if (circ) 00946 chromatism = 0; /* Chromatism correction unrequired for 00947 circular polarimetry */ 00948 00949 00950 nscience = pmos; 00951 00952 reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00953 rerrors = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00954 slitss = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience); 00955 mappeds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00956 skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience); 00957 00958 if (pmos) { 00959 cpl_msg_info(recipe, "PMOS data found"); 00960 if (standard) { 00961 science_tag = "STANDARD_PMOS"; 00962 reduced_science_tag = "REDUCED_STD_PMOS"; 00963 unmapped_science_tag = "UNMAPPED_STD_PMOS"; 00964 mapped_science_tag = "MAPPED_STD_PMOS"; 00965 mapped_science_sky_tag = "MAPPED_ALL_STD_PMOS"; 00966 skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_PMOS"; 00967 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_PMOS"; 00968 disp_coeff_sky_tag = "DISP_COEFF_STD_PMOS"; 00969 mapped_sky_tag = "MAPPED_SKY_STD_PMOS"; 00970 unmapped_sky_tag = "UNMAPPED_SKY_STD_PMOS"; 00971 object_table_tag = "OBJECT_TABLE_STD_PMOS"; 00972 object_table_pol_tag = "OBJECT_TABLE_POL_STD_PMOS"; 00973 reduced_sky_tag = "REDUCED_SKY_STD_PMOS"; 00974 reduced_error_tag = "REDUCED_ERROR_STD_PMOS"; 00975 reduced_q_tag = "REDUCED_Q_STD_PMOS"; 00976 reduced_u_tag = "REDUCED_U_STD_PMOS"; 00977 reduced_v_tag = "REDUCED_V_STD_PMOS"; 00978 reduced_l_tag = "REDUCED_L_STD_PMOS"; 00979 reduced_i_tag = "REDUCED_I_STD_PMOS"; 00980 reduced_error_q_tag = "REDUCED_ERROR_Q_STD_PMOS"; 00981 reduced_error_u_tag = "REDUCED_ERROR_U_STD_PMOS"; 00982 reduced_error_v_tag = "REDUCED_ERROR_V_STD_PMOS"; 00983 reduced_error_l_tag = "REDUCED_ERROR_L_STD_PMOS"; 00984 reduced_error_i_tag = "REDUCED_ERROR_I_STD_PMOS"; 00985 reduced_nul_q_tag = "REDUCED_NUL_Q_STD_PMOS"; 00986 reduced_nul_u_tag = "REDUCED_NUL_U_STD_PMOS"; 00987 reduced_nul_v_tag = "REDUCED_NUL_V_STD_PMOS"; 00988 reduced_angle_tag = "REDUCED_ANGLE_STD_PMOS"; 00989 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS"; 00990 } 00991 else { 00992 science_tag = "SCIENCE_PMOS"; 00993 reduced_science_tag = "REDUCED_SCI_PMOS"; 00994 unmapped_science_tag = "UNMAPPED_SCI_PMOS"; 00995 mapped_science_tag = "MAPPED_SCI_PMOS"; 00996 mapped_science_sky_tag = "MAPPED_ALL_SCI_PMOS"; 00997 skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_PMOS"; 00998 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_PMOS"; 00999 disp_coeff_sky_tag = "DISP_COEFF_SCI_PMOS"; 01000 mapped_sky_tag = "MAPPED_SKY_SCI_PMOS"; 01001 unmapped_sky_tag = "UNMAPPED_SKY_SCI_PMOS"; 01002 object_table_tag = "OBJECT_TABLE_SCI_PMOS"; 01003 object_table_pol_tag = "OBJECT_TABLE_POL_SCI_PMOS"; 01004 reduced_sky_tag = "REDUCED_SKY_SCI_PMOS"; 01005 reduced_error_tag = "REDUCED_ERROR_SCI_PMOS"; 01006 reduced_q_tag = "REDUCED_Q_SCI_PMOS"; 01007 reduced_u_tag = "REDUCED_U_SCI_PMOS"; 01008 reduced_v_tag = "REDUCED_V_SCI_PMOS"; 01009 reduced_l_tag = "REDUCED_L_SCI_PMOS"; 01010 reduced_i_tag = "REDUCED_I_SCI_PMOS"; 01011 reduced_error_q_tag = "REDUCED_ERROR_Q_SCI_PMOS"; 01012 reduced_error_u_tag = "REDUCED_ERROR_U_SCI_PMOS"; 01013 reduced_error_v_tag = "REDUCED_ERROR_V_SCI_PMOS"; 01014 reduced_error_l_tag = "REDUCED_ERROR_L_SCI_PMOS"; 01015 reduced_error_i_tag = "REDUCED_ERROR_I_SCI_PMOS"; 01016 reduced_nul_q_tag = "REDUCED_NUL_Q_SCI_PMOS"; 01017 reduced_nul_u_tag = "REDUCED_NUL_U_SCI_PMOS"; 01018 reduced_nul_v_tag = "REDUCED_NUL_V_SCI_PMOS"; 01019 reduced_angle_tag = "REDUCED_ANGLE_SCI_PMOS"; 01020 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS"; 01021 } 01022 01023 master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS"; 01024 disp_coeff_tag = "DISP_COEFF_PMOS"; 01025 curv_coeff_tag = "CURV_COEFF_PMOS"; 01026 slit_location_tag = "SLIT_LOCATION_PMOS"; 01027 01028 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) { 01029 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_PMOS"; 01030 disp_coeff_tag = "DISP_COEFF_LONG_PMOS"; 01031 slit_location_tag = "SLIT_LOCATION_LONG_PMOS"; 01032 } 01033 } 01034 01035 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0) 01036 fors_pmos_science_exit("Missing required input: MASTER_BIAS"); 01037 01038 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1) 01039 fors_pmos_science_exit("Too many in input: MASTER_BIAS"); 01040 01041 if (skyalign >= 0) 01042 if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1) 01043 fors_pmos_science_exit("Too many in input: MASTER_SKYLINECAT"); 01044 01045 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) == 0) { 01046 cpl_msg_error(recipe, "Missing required input: %s", disp_coeff_tag); 01047 fors_pmos_science_exit(NULL); 01048 } 01049 01050 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) > 1) { 01051 cpl_msg_error(recipe, "Too many in input: %s", disp_coeff_tag); 01052 fors_pmos_science_exit(NULL); 01053 } 01054 01055 if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) { 01056 cpl_msg_error(recipe, "Missing required input: %s", 01057 slit_location_tag); 01058 fors_pmos_science_exit(NULL); 01059 } 01060 01061 if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) { 01062 cpl_msg_error(recipe, "Too many in input: %s", slit_location_tag); 01063 fors_pmos_science_exit(NULL); 01064 } 01065 01066 if (chromatism) { 01067 if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) { 01068 cpl_msg_error(recipe, "Missing required input: %s", 01069 chrom_table_tag); 01070 fors_pmos_science_exit(NULL); 01071 } 01072 01073 if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) { 01074 cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag); 01075 fors_pmos_science_exit(NULL); 01076 } 01077 } 01078 01079 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) { 01080 if (flatfield) { 01081 cpl_msg_error(recipe, "Too many in input: %s", 01082 master_norm_flat_tag); 01083 fors_pmos_science_exit(NULL); 01084 } 01085 else { 01086 cpl_msg_warning(recipe, "%s in input are ignored, " 01087 "since flat field correction was not requested", 01088 master_norm_flat_tag); 01089 } 01090 } 01091 01092 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) { 01093 if (!flatfield) { 01094 cpl_msg_warning(recipe, "%s in input is ignored, " 01095 "since flat field correction was not requested", 01096 master_norm_flat_tag); 01097 } 01098 } 01099 01100 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) { 01101 if (flatfield) { 01102 cpl_msg_error(recipe, "Flat field correction was requested, " 01103 "but no %s are found in input", 01104 master_norm_flat_tag); 01105 fors_pmos_science_exit(NULL); 01106 } 01107 } 01108 01109 if (standard) { 01110 if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) > 1) { 01111 cpl_msg_error(recipe, "Too many in input: %s", std_pmos_table_tag); 01112 fors_pmos_science_exit(NULL); 01113 } 01114 01115 if (qc) { 01116 if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) == 0) { 01117 cpl_msg_error(recipe, "QC computation was requested, but no " 01118 "%s is found in input", std_pmos_table_tag); 01119 fors_pmos_science_exit(NULL); 01120 } 01121 } 01122 } 01123 01124 cpl_msg_indent_less(); 01125 01126 01127 /* 01128 * Get the reference wavelength and the rebin factor along the 01129 * dispersion direction from a scientific exposure 01130 */ 01131 01132 header = dfs_load_header(frameset, science_tag, 0); 01133 01134 if (header == NULL) 01135 fors_pmos_science_exit("Cannot load scientific frame header"); 01136 01137 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 01138 if (instrume == NULL) 01139 fors_pmos_science_exit("Missing keyword INSTRUME in scientific header"); 01140 instrume = cpl_strdup(instrume); 01141 01142 if (instrume[4] == '1') 01143 snprintf(version, 80, "%s/%s", "fors1", VERSION); 01144 if (instrume[4] == '2') 01145 snprintf(version, 80, "%s/%s", "fors2", VERSION); 01146 01147 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 01148 01149 if (cpl_error_get_code() != CPL_ERROR_NONE) 01150 fors_pmos_science_exit("Missing keyword ESO INS GRIS1 WLEN in scientific " 01151 "frame header"); 01152 01153 if (reference < 3000.0) /* Perhaps in nanometers... */ 01154 reference *= 10; 01155 01156 if (reference < 3000.0 || reference > 13000.0) { 01157 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 01158 "keyword ESO INS GRIS1 WLEN in scientific frame header", 01159 reference); 01160 fors_pmos_science_exit(NULL); 01161 } 01162 01163 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 01164 01165 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 01166 01167 if (cpl_error_get_code() != CPL_ERROR_NONE) 01168 fors_pmos_science_exit("Missing keyword ESO DET WIN1 BINX in " 01169 "scientific frame header"); 01170 01171 if (rebin != 1) { 01172 dispersion *= rebin; 01173 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01174 "spectral dispersion used is %f A/pixel", rebin, 01175 dispersion); 01176 ext_radius /= rebin; 01177 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 01178 "extraction radius used is %d pixel", rebin, 01179 ext_radius); 01180 } 01181 01182 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD"); 01183 01184 if (cpl_error_get_code() != CPL_ERROR_NONE) 01185 fors_pmos_science_exit("Missing keyword ESO DET OUT1 CONAD in " 01186 "scientific frame header"); 01187 01188 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain); 01189 01190 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON"); 01191 01192 if (cpl_error_get_code() != CPL_ERROR_NONE) 01193 fors_pmos_science_exit("Missing keyword ESO DET OUT1 RON in " 01194 "scientific frame header"); 01195 01196 ron /= gain; /* Convert from electrons to ADU */ 01197 01198 cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron); 01199 01200 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) { 01201 cpl_msg_error(recipe, "Missing required input: %s", curv_coeff_tag); 01202 fors_pmos_science_exit(NULL); 01203 } 01204 01205 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) { 01206 cpl_msg_error(recipe, "Too many in input: %s", curv_coeff_tag); 01207 fors_pmos_science_exit(NULL); 01208 } 01209 01210 cpl_msg_info(recipe, "Load normalised flat field (if present)..."); 01211 cpl_msg_indent_more(); 01212 01213 if (flatfield) { 01214 norm_flat = dfs_load_image(frameset, master_norm_flat_tag, 01215 CPL_TYPE_FLOAT, 0, 1); 01216 } 01217 01218 if (skyalign >= 0) { 01219 01220 cpl_msg_indent_less(); 01221 cpl_msg_info(recipe, "Load input sky line catalog..."); 01222 cpl_msg_indent_more(); 01223 01224 wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1); 01225 01226 if (wavelengths) { 01227 /* 01228 * Cast the wavelengths into a (double precision) CPL vector 01229 */ 01230 01231 nlines = cpl_table_get_nrow(wavelengths); 01232 01233 if (nlines == 0) 01234 fors_pmos_science_exit("Empty input sky line catalog"); 01235 01236 if (cpl_table_has_column(wavelengths, wcolumn) != 1) { 01237 cpl_msg_error(recipe, "Missing column %s in input line " 01238 "catalog table", wcolumn); 01239 fors_pmos_science_exit(NULL); 01240 } 01241 01242 line = cpl_malloc(nlines * sizeof(double)); 01243 01244 for (i = 0; i < nlines; i++) 01245 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL); 01246 01247 cpl_table_delete(wavelengths); wavelengths = NULL; 01248 01249 lines = cpl_vector_wrap(nlines, line); 01250 } 01251 else { 01252 cpl_msg_info(recipe, "No sky line catalog found in input - fine!"); 01253 } 01254 } 01255 01256 /* 01257 * Keep a table of slit positions according to science, in order to 01258 * check its consistency with those from arc and flat. 01259 */ 01260 01261 mask_science = mos_load_slits_fors_mos(header, &nslits_out_det); 01262 01263 cpl_propertylist_delete(header); header = NULL; 01264 01265 cpl_table_name_column(mask_science, "xtop", "science"); 01266 01267 /* 01268 * Load the wavelength calibration table 01269 */ 01270 01271 idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1); 01272 01273 if (idscoeff == NULL) 01274 fors_pmos_science_exit("Cannot load wavelength calibration table"); 01275 01276 /* 01277 * Keep a table of slit positions according to arc, in order to 01278 * check its consistency with those from science and flat. 01279 */ 01280 01281 header = dfs_load_header(frameset, disp_coeff_tag, 0); 01282 01283 mask_arc = mos_load_slits_fors_mos(header, &nslits_out_det); 01284 01285 cpl_propertylist_delete(header); header = NULL; 01286 01287 if (cpl_table_move_column(mask_science, "xtop", mask_arc)) { 01288 cpl_error_reset(); 01289 cpl_msg_warning(recipe, 01290 "Slit configuration of science and arc differs!"); 01291 cpl_table_delete(mask_arc); mask_arc = NULL; 01292 goto skip; 01293 } 01294 cpl_table_name_column(mask_science, "xtop", "arc"); 01295 cpl_table_delete(mask_arc); mask_arc = NULL; 01296 01297 if (norm_flat) { 01298 01299 /* 01300 * Keep a table of slit positions according to arc, in order to 01301 * check its consistency with those from science and flat. 01302 */ 01303 01304 header = dfs_load_header(frameset, master_norm_flat_tag, 0); 01305 01306 mask_flat = mos_load_slits_fors_mos(header, &nslits_out_det); 01307 01308 cpl_propertylist_delete(header); header = NULL; 01309 01310 if (cpl_table_move_column(mask_science, "xtop", mask_flat)) { 01311 cpl_error_reset(); 01312 cpl_msg_warning(recipe, 01313 "Slit configuration of science and flat differs!"); 01314 cpl_table_delete(mask_flat); mask_flat = NULL; 01315 goto skip; 01316 } 01317 cpl_table_name_column(mask_science, "xtop", "flat"); 01318 cpl_table_delete(mask_flat); mask_flat = NULL; 01319 } 01320 01321 cpl_table_duplicate_column(mask_science, "diff", mask_science, "science"); 01322 cpl_table_subtract_columns(mask_science, "diff", "arc"); 01323 cpl_table_abs_column(mask_science, "diff"); 01324 01325 if (cpl_table_get_column_max(mask_science, "diff") > 0.01) { 01326 cpl_msg_warning(recipe, 01327 "Slit configuration of science and arc differs!"); 01328 goto skip; 01329 } 01330 01331 if (norm_flat) { 01332 cpl_table_erase_column(mask_science, "diff"); 01333 01334 cpl_table_duplicate_column(mask_science, "diff", 01335 mask_science, "science"); 01336 cpl_table_subtract_columns(mask_science, "diff", "flat"); 01337 cpl_table_abs_column(mask_science, "diff"); 01338 01339 if (cpl_table_get_column_max(mask_science, "diff") > 0.01) { 01340 cpl_msg_warning(recipe, 01341 "Slit configuration of science and flat differs!"); 01342 goto skip; 01343 } 01344 } 01345 01346 skip: 01347 01348 cpl_table_delete(mask_science); mask_science = NULL; 01349 01350 for (j = 0; j < nscience; j++) { 01351 int k; 01352 01353 cpl_msg_indent_less(); 01354 cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f " 01355 "(%d out of %d) ...", 01356 angles[j], j + 1, nscience); 01357 cpl_msg_indent_more(); 01358 01359 cpl_msg_info(recipe, "Load scientific exposure..."); 01360 cpl_msg_indent_more(); 01361 01362 01363 /* 01364 * FIXME: Horrible workaround to avoid the problem because of the 01365 * multiple encapsulation of cpl_frameset_find() in different 01366 * loading functions 01367 */ 01368 01369 header = dfs_load_header(frameset, science_tag, 0); 01370 01371 for (k = 0; k < j; k ++) { 01372 cpl_propertylist_delete(header); 01373 header = dfs_load_header(frameset, NULL, 0); 01374 } 01375 01376 spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0); 01377 01378 for (k = 0; k < j; k ++) { 01379 cpl_image_delete(spectra); 01380 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0); 01381 } 01382 01383 if (spectra == NULL) 01384 fors_pmos_science_exit("Cannot load scientific frame"); 01385 01386 if (header == NULL) 01387 fors_pmos_science_exit("Cannot load scientific frame header"); 01388 01389 alltime = cpl_propertylist_get_double(header, "EXPTIME"); 01390 01391 if (cpl_error_get_code() != CPL_ERROR_NONE) 01392 fors_pmos_science_exit("Missing keyword EXPTIME in scientific " 01393 "frame header"); 01394 01395 cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s", 01396 alltime); 01397 01398 ra = cpl_propertylist_get_double(header, "RA"); 01399 dec = cpl_propertylist_get_double(header, "DEC"); 01400 01401 if (cpl_error_get_code() != CPL_ERROR_NONE) 01402 fors_pmos_science_exit("Missing keywords RA and DEC in scientific " 01403 "frame header"); 01404 01405 /* Leave the header on for the next step... */ 01406 01407 cpl_msg_indent_less(); 01408 01409 /* 01410 * Remove the master bias 01411 */ 01412 01413 cpl_msg_info(recipe, "Remove the master bias..."); 01414 01415 bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1); 01416 01417 if (bias == NULL) 01418 fors_pmos_science_exit("Cannot load master bias"); 01419 01420 if (doit) { 01421 if (j == 0) 01422 blevel = cpl_image_get_mean(bias); 01423 mos_randomise_image(spectra, ron, gain, blevel); 01424 } 01425 01426 overscans = mos_load_overscans_fors(header); 01427 01428 dummy = mos_remove_bias(spectra, bias, overscans); 01429 cpl_image_delete(spectra); spectra = dummy; dummy = NULL; 01430 cpl_image_delete(bias); bias = NULL; 01431 cpl_table_delete(overscans); overscans = NULL; 01432 01433 if (spectra == NULL) 01434 fors_pmos_science_exit("Cannot remove bias from scientific frame"); 01435 01436 ccd_xsize = nx = cpl_image_get_size_x(spectra); 01437 ccd_ysize = ny = cpl_image_get_size_y(spectra); 01438 01439 if (flatfield) { 01440 01441 if (norm_flat) { 01442 cpl_msg_info(recipe, "Apply flat field correction..."); 01443 if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) { 01444 cpl_msg_error(recipe, 01445 "Failure of flat field correction: %s", 01446 cpl_error_get_message()); 01447 fors_pmos_science_exit(NULL); 01448 } 01449 } 01450 else { 01451 cpl_msg_error(recipe, "Cannot load input %s for flat field " 01452 "correction", master_norm_flat_tag); 01453 fors_pmos_science_exit(NULL); 01454 } 01455 01456 } 01457 01458 /* 01459 * Load the spectral curvature table 01460 */ 01461 01462 polytraces = dfs_load_table(frameset, curv_coeff_tag, 1); 01463 if (polytraces == NULL) 01464 fors_pmos_science_exit("Cannot load spectral curvature table"); 01465 01466 /* 01467 * Load the slit location table 01468 */ 01469 01470 slits = dfs_load_table(frameset, slit_location_tag, 1); 01471 if (slits == NULL) 01472 fors_pmos_science_exit("Cannot load slits location table"); 01473 01474 cpl_msg_info(recipe, "Processing scientific spectra..."); 01475 01476 /* 01477 * This one will also generate the spatial map from the spectral 01478 * curvature table (in the case of multislit data) 01479 */ 01480 01481 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 01482 01483 smapped = mos_spatial_calibration(spectra, slits, polytraces, 01484 reference, startwavelength, 01485 endwavelength, dispersion, 01486 flux, coordinate); 01487 01488 /* 01489 * Generate a rectified wavelength map from the wavelength calibration 01490 * table 01491 */ 01492 01493 rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength, 01494 endwavelength); 01495 01496 if (dispersion > 1.0) 01497 highres = 0; 01498 else 01499 highres = 1; 01500 01501 if (skyalign >= 0) { 01502 if (skyalign) { 01503 cpl_msg_info(recipe, 01504 "Align wavelength solution to reference skylines " 01505 "applying %d order residual fit...", skyalign); 01506 } 01507 else { 01508 cpl_msg_info(recipe, "Align wavelength solution to reference " 01509 "skylines applying median offset..."); 01510 } 01511 01512 if (!j) { 01513 offsets = mos_wavelength_align(smapped, slits, reference, 01514 startwavelength, endwavelength, 01515 idscoeff, lines, highres, 01516 skyalign, rainbow, 4); 01517 if (offsets) { 01518 if (standard) 01519 cpl_msg_warning(recipe, "Alignment of the wavelength " 01520 "solution to reference sky lines may " 01521 "be unreliable in this case!"); 01522 01523 if (dfs_save_table(frameset, offsets, skylines_offsets_tag, 01524 NULL, parlist, recipe, version)) { 01525 fors_pmos_science_exit(NULL); 01526 } 01527 01528 } else { 01529 cpl_msg_warning(recipe, "Alignment of the wavelength " 01530 "solution to reference sky lines could " 01531 "not be done!"); 01532 skyalign = -1; 01533 } 01534 } 01535 01536 01537 } 01538 01539 wavemap = mos_map_wavelengths(coordinate, rainbow, slits, 01540 polytraces, reference, 01541 startwavelength, endwavelength, 01542 dispersion); 01543 01544 01545 cpl_image_delete(rainbow); rainbow = NULL; 01546 cpl_image_delete(coordinate); coordinate = NULL; 01547 01548 /* 01549 * Here the wavelength calibrated slit spectra are created. This frame 01550 * contains sky_science. 01551 */ 01552 01553 mapped_sky = mos_wavelength_calibration(smapped, reference, 01554 startwavelength, endwavelength, 01555 dispersion, idscoeff, flux); 01556 01557 if (!j) { 01558 cpl_msg_indent_less(); 01559 cpl_msg_info(recipe, 01560 "Check applied wavelength against skylines..."); 01561 cpl_msg_indent_more(); 01562 01563 mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength, 01564 dispersion, 6, highres); 01565 01566 01567 cpl_msg_info(recipe, "Mean residual: %f", mean_rms); 01568 01569 mean_rms = cpl_table_get_column_mean(idscoeff, "error"); 01570 01571 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)", 01572 mean_rms, mean_rms * dispersion); 01573 } 01574 01575 save_header = cpl_propertylist_duplicate(header); 01576 01577 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01578 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01579 cpl_propertylist_update_double(header, "CRVAL1", 01580 startwavelength + dispersion/2); 01581 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01582 cpl_propertylist_update_double(header, "CD1_1", dispersion); 01583 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01584 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01585 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01586 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01587 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01588 01589 if (time_normalise) { 01590 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime); 01591 01592 if (!j) { 01593 if(dfs_save_image_null(frameset, parlist, 01594 mapped_science_sky_tag, 01595 recipe, version)) { 01596 fors_pmos_science_exit(NULL); 01597 } 01598 } 01599 01600 if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) { 01601 fors_pmos_science_exit(NULL); 01602 } 01603 01604 cpl_image_delete(dummy); dummy = NULL; 01605 } 01606 else { 01607 01608 if (!j) { 01609 if(dfs_save_image_null(frameset, parlist, 01610 mapped_science_sky_tag, 01611 recipe, version)) { 01612 fors_pmos_science_exit(NULL); 01613 } 01614 } 01615 01616 if (dfs_save_image_ext(mapped_sky, 01617 mapped_science_sky_tag, header)) { 01618 fors_pmos_science_exit(NULL); 01619 } 01620 01621 } 01622 01623 if (skymedian == 0 && skylocal == 0) { 01624 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01625 } 01626 01627 if (skylocal) { 01628 01629 cpl_msg_indent_less(); 01630 01631 cpl_msg_info(recipe, "Local sky determination..."); 01632 cpl_msg_indent_more(); 01633 skymap = mos_subtract_sky(spectra, slits, polytraces, reference, 01634 startwavelength, endwavelength, dispersion); 01635 01636 if (skymap) { 01637 if (time_normalise) 01638 cpl_image_divide_scalar(skymap, alltime); 01639 01640 if (!j) { 01641 if(dfs_save_image_null(frameset, parlist, 01642 unmapped_sky_tag, 01643 recipe, version)) { 01644 fors_pmos_science_exit(NULL); 01645 } 01646 } 01647 01648 if (dfs_save_image_ext(skymap, unmapped_sky_tag, 01649 save_header)) { 01650 fors_pmos_science_exit(NULL); 01651 } 01652 01653 cpl_image_delete(skymap); skymap = NULL; 01654 01655 if (!j) { 01656 if(dfs_save_image_null(frameset, parlist, 01657 unmapped_science_tag, 01658 recipe, version)) { 01659 fors_pmos_science_exit(NULL); 01660 } 01661 } 01662 01663 if (dfs_save_image_ext(spectra, unmapped_science_tag, 01664 save_header)) { 01665 fors_pmos_science_exit(NULL); 01666 } 01667 01668 if (cosmics) { 01669 cpl_msg_info(recipe, "Removing cosmic rays..."); 01670 mos_clean_cosmics(spectra, gain, -1., -1.); 01671 } 01672 01673 /* 01674 * The spatially rectified image, that contained the sky, 01675 * is replaced by a sky-subtracted spatially rectified image: 01676 */ 01677 01678 cpl_image_delete(smapped); smapped = NULL; 01679 01680 smapped = mos_spatial_calibration(spectra, slits, polytraces, 01681 reference, startwavelength, 01682 endwavelength, dispersion, 01683 flux, NULL); 01684 } 01685 else { 01686 cpl_msg_warning(recipe, "Sky subtraction failure"); 01687 if (cosmics) 01688 cpl_msg_warning(recipe, 01689 "Cosmic rays removal not performed!"); 01690 cosmics = skylocal = 0; 01691 } 01692 } 01693 01694 cpl_image_delete(spectra); spectra = NULL; 01695 cpl_table_delete(polytraces); polytraces = NULL; 01696 01697 if (skyalign >= 0) { 01698 save_header = dfs_load_header(frameset, science_tag, 0); 01699 01700 if (!j) { 01701 if(dfs_save_image_null(frameset, parlist, 01702 wavelength_map_sky_tag, 01703 recipe, version)) { 01704 fors_pmos_science_exit(NULL); 01705 } 01706 } 01707 01708 if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag, 01709 save_header)) { 01710 fors_pmos_science_exit(NULL); 01711 } 01712 } 01713 01714 cpl_image_delete(wavemap); wavemap = NULL; 01715 01716 mapped = mos_wavelength_calibration(smapped, reference, 01717 startwavelength, endwavelength, 01718 dispersion, idscoeff, flux); 01719 01720 cpl_image_delete(smapped); smapped = NULL; 01721 01722 if (skyalign >= 0) { 01723 if (!j) { 01724 if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag, 01725 NULL, parlist, recipe, version)) { 01726 fors_pmos_science_exit(NULL); 01727 } 01728 } 01729 } 01730 01731 if (skymedian) { 01732 cpl_msg_indent_less(); 01733 cpl_msg_info(recipe, "Local sky determination..."); 01734 cpl_msg_indent_more(); 01735 01736 skylocalmap = mos_sky_local_old(mapped, slits); 01737 cpl_image_subtract(mapped, skylocalmap); 01738 cpl_image_delete(skylocalmap); skylocalmap = NULL; 01739 } 01740 01741 if (skymedian || skylocal) { 01742 01743 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped); 01744 01745 cpl_image_delete(mapped_sky); mapped_sky = NULL; 01746 01747 if (time_normalise) { 01748 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime); 01749 01750 if (!j) { 01751 if(dfs_save_image_null(frameset, parlist, 01752 mapped_sky_tag, 01753 recipe, version)) { 01754 fors_pmos_science_exit(NULL); 01755 } 01756 } 01757 01758 if (dfs_save_image_ext(dummy, mapped_sky_tag, 01759 header)) { 01760 fors_pmos_science_exit(NULL); 01761 } 01762 01763 cpl_image_delete(dummy); dummy = NULL; 01764 } 01765 else { 01766 if (!j) { 01767 if(dfs_save_image_null(frameset, parlist, 01768 mapped_sky_tag, 01769 recipe, version)) { 01770 fors_pmos_science_exit(NULL); 01771 } 01772 } 01773 01774 if (dfs_save_image_ext(skylocalmap, mapped_sky_tag, 01775 header)) { 01776 fors_pmos_science_exit(NULL); 01777 } 01778 } 01779 01780 skylocalmaps[j] = skylocalmap; 01781 01782 cpl_msg_indent_less(); 01783 cpl_msg_info(recipe, "Object detection..."); 01784 cpl_msg_indent_more(); 01785 01786 if (!j) { 01787 origslits = cpl_table_duplicate(slits); 01788 nslits = cpl_table_get_nrow(slits); 01789 } 01790 01791 if (cosmics || nscience > 1) { 01792 dummy = mos_detect_objects(mapped, slits, slit_margin, 01793 ext_radius, cont_radius); 01794 } 01795 else { 01796 mapped_cleaned = cpl_image_duplicate(mapped); 01797 mos_clean_cosmics(mapped_cleaned, gain, -1., -1.); 01798 dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin, 01799 ext_radius, cont_radius); 01800 01801 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL; 01802 } 01803 01804 cpl_image_delete(dummy); dummy = NULL; 01805 01806 } 01807 01808 slitss[j] = slits; 01809 mappeds[j] = mapped; 01810 01811 cpl_msg_indent_less(); 01812 01813 cpl_propertylist_delete(header); header = NULL; 01814 cpl_propertylist_delete(save_header); save_header = NULL; 01815 } 01816 01817 cpl_table_delete(offsets); offsets = NULL; 01818 cpl_table_delete(idscoeff); idscoeff = NULL; 01819 01820 cpl_image_delete(norm_flat); norm_flat = NULL; 01821 cpl_vector_delete(lines); lines = NULL; 01822 01823 01824 cpl_msg_indent_less(); 01825 cpl_msg_info(recipe, 01826 "Check object detection in both beams for all angles..."); 01827 cpl_msg_indent_more(); 01828 01829 /* 01830 * House keeping - selection of objects for which information required 01831 * for Stokes parameters computation is present 01832 */ 01833 01834 error = mos_object_intersect(slitss, origslits, nscience, tolerance); 01835 if (error == CPL_ERROR_DATA_NOT_FOUND) { 01836 cpl_msg_warning(recipe, "No objects found: no Stokes " 01837 "parameters to compute!"); 01838 for (j = 0; j < nscience; j++) 01839 cpl_table_delete(slitss[j]); 01840 cpl_free(slitss); 01841 cpl_table_delete(origslits); 01842 return 0; 01843 } else if (error) { 01844 fors_pmos_science_exit("Problem in polarimetric object selection"); 01845 } 01846 01847 if (dfs_save_table(frameset, origslits, object_table_pol_tag, 01848 NULL, parlist, recipe, version)) { 01849 fors_pmos_science_exit(NULL); 01850 } 01851 01852 /* 01853 * Save also object tables per angle after intersection 01854 */ 01855 01856 for (j = 0; j < nscience; j++) { 01857 if (!j) { 01858 if(dfs_save_image_null(frameset, parlist, object_table_tag, 01859 recipe, version)) { 01860 fors_pmos_science_exit(NULL); 01861 } 01862 } 01863 01864 if (dfs_save_table_ext(slitss[j], object_table_tag, NULL)) { 01865 fors_pmos_science_exit(NULL); 01866 } 01867 } 01868 01869 nobjs_per_slit = fors_get_nobjs_perslit(origslits); 01870 01871 cpl_msg_indent_less(); 01872 cpl_msg_info(recipe, "Object extraction..."); 01873 cpl_msg_indent_more(); 01874 01875 for (j = 0; j < nscience; j++) { 01876 int k; 01877 01878 header = dfs_load_header(frameset, science_tag, 0); 01879 01880 for (k = 0; k < j; k ++) { 01881 cpl_propertylist_delete(header); 01882 header = dfs_load_header(frameset, NULL, 0); 01883 } 01884 01885 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 01886 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 01887 cpl_propertylist_update_double(header, "CRVAL1", 01888 startwavelength + (dispersion * group)/2); 01889 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 01890 cpl_propertylist_update_double(header, "CD1_1", dispersion * group); 01891 cpl_propertylist_update_double(header, "CD1_2", 0.0); 01892 cpl_propertylist_update_double(header, "CD2_1", 0.0); 01893 cpl_propertylist_update_double(header, "CD2_2", 1.0); 01894 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 01895 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 01896 01897 if (skymedian || skylocal) { 01898 01899 cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...", 01900 angles[j], j + 1, nscience); 01901 01902 images = mos_extract_objects(mappeds[j], skylocalmaps[j], 01903 origslits, 01904 ext_mode, ron, gain, 1); 01905 01906 cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL; 01907 01908 if (images) { 01909 if (time_normalise) 01910 cpl_image_divide_scalar(images[0], alltime); 01911 01912 mos_rebin_signal(images, group); 01913 01914 if (!j) { 01915 if(dfs_save_image_null(frameset, parlist, 01916 reduced_science_tag, 01917 recipe, version)) { 01918 fors_pmos_science_exit(NULL); 01919 } 01920 } 01921 01922 if (dfs_save_image_ext(images[0], reduced_science_tag, 01923 header)) { 01924 fors_pmos_science_exit(NULL); 01925 } 01926 01927 reduceds[j] = images[0]; 01928 01929 if (time_normalise) 01930 cpl_image_divide_scalar(images[1], alltime); 01931 01932 mos_rebin_signal(images + 1, group); 01933 01934 if (!j) { 01935 if(dfs_save_image_null(frameset, parlist, 01936 reduced_sky_tag, 01937 recipe, version)) { 01938 fors_pmos_science_exit(NULL); 01939 } 01940 } 01941 01942 if (dfs_save_image_ext(images[1], reduced_sky_tag, 01943 header)) { 01944 fors_pmos_science_exit(NULL); 01945 } 01946 cpl_image_delete(images[1]); 01947 01948 if (time_normalise) 01949 cpl_image_divide_scalar(images[2], alltime); 01950 01951 mos_rebin_error(images + 2, group); 01952 01953 if (!j) { 01954 if(dfs_save_image_null(frameset, parlist, 01955 reduced_error_tag, 01956 recipe, version)) { 01957 fors_pmos_science_exit(NULL); 01958 } 01959 } 01960 01961 if (dfs_save_image_ext(images[2], reduced_error_tag, 01962 header)) { 01963 fors_pmos_science_exit(NULL); 01964 } 01965 01966 rerrors[j] = images[2]; 01967 01968 cpl_free(images); 01969 } 01970 else { 01971 cpl_msg_warning(recipe, "No objects found: the products " 01972 "%s, %s, and %s are not created", 01973 reduced_science_tag, reduced_sky_tag, 01974 reduced_error_tag); 01975 } 01976 01977 } 01978 01979 if (skymedian || skylocal) { 01980 if (time_normalise) 01981 cpl_image_divide_scalar(mappeds[j], alltime); 01982 01983 if (!j) { 01984 if(dfs_save_image_null(frameset, parlist, 01985 mapped_science_tag, 01986 recipe, version)) { 01987 fors_pmos_science_exit(NULL); 01988 } 01989 } 01990 01991 if (dfs_save_image_ext(mappeds[j], mapped_science_tag, 01992 header)) { 01993 fors_pmos_science_exit(NULL); 01994 } 01995 } 01996 01997 cpl_image_delete(mappeds[j]); mappeds[j] = NULL; 01998 cpl_propertylist_delete(header); header = NULL; 01999 02000 } 02001 02002 cpl_table_delete(origslits); 02003 02004 /* Stokes computation */ 02005 02006 nobjects = cpl_image_get_size_y(reduceds[0]) / 2; 02007 nx = cpl_image_get_size_x(reduceds[0]); 02008 02009 header = cpl_propertylist_new(); 02010 cpl_propertylist_update_double(header, "CRPIX1", 1.0); 02011 cpl_propertylist_update_double(header, "CRPIX2", 1.0); 02012 cpl_propertylist_update_double(header, "CRVAL1", 02013 startwavelength + (dispersion * group)/2); 02014 cpl_propertylist_update_double(header, "CRVAL2", 1.0); 02015 cpl_propertylist_update_double(header, "CD1_1", dispersion * group); 02016 cpl_propertylist_update_double(header, "CD1_2", 0.0); 02017 cpl_propertylist_update_double(header, "CD2_1", 0.0); 02018 cpl_propertylist_update_double(header, "CD2_2", 1.0); 02019 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR"); 02020 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL"); 02021 02022 if (circ) { 02023 02024 cpl_image *pv_im = NULL; 02025 cpl_image *pi_im = NULL; 02026 cpl_image *pvnull_im = NULL; 02027 cpl_image *pierr_im = NULL; 02028 cpl_image *perr_im = NULL; 02029 02030 double *p_v = NULL; 02031 double *p_i = NULL; 02032 double *p_vnull = NULL; 02033 double *perr = NULL; 02034 double *pierr = NULL; 02035 02036 double mean_vnull; 02037 02038 int p = -1; 02039 int total = 0; 02040 02041 pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02042 perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02043 pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02044 pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02045 02046 p_v = cpl_image_get_data_double(pv_im); 02047 perr = cpl_image_get_data_double(perr_im); 02048 p_i = cpl_image_get_data_double(pi_im); 02049 pierr = cpl_image_get_data_double(pierr_im); 02050 02051 if (nscience / 2 > 1) { 02052 pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02053 p_vnull = cpl_image_get_data_double(pvnull_im); 02054 } 02055 02056 for (j = 0; j < nobjects; j++) { 02057 02058 FILE *file; // Bagoo 02059 char *filename; // Bagoo 02060 02061 int k, m; 02062 02063 double * ip_v, * ip_i, * ipierr, 02064 * ip_vnull, * iperr; 02065 02066 float * data; 02067 float * iff, * ierr; 02068 02069 ip_v = p_v + (nobjects - 1 - j) * nx; 02070 02071 if (nscience / 2 > 1) 02072 ip_vnull = p_vnull + (nobjects - 1 - j) * nx; 02073 02074 iperr = perr + (nobjects - 1 - j) * nx; 02075 02076 ip_i = p_i + (nobjects - 1 - j) * nx; 02077 ipierr = pierr + (nobjects - 1 - j) * nx; 02078 02079 total = 0; 02080 for (i = 0; i < nslits; i += 2) { 02081 total += nobjs_per_slit[i]; 02082 if (total > j) { 02083 p = i; 02084 break; 02085 } 02086 } 02087 02088 for (k = 0; k < nscience / 2; k++) { 02089 float *if_o, *if_e, *ifdelta_o, *ifdelta_e; 02090 float *if_o_err, *if_e_err, *ifdelta_o_err, *ifdelta_e_err; 02091 02092 int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45); 02093 int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45); 02094 02095 02096 data = cpl_image_get_data_float(reduceds[pos]); 02097 02098 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02099 + (total - j - 1)) * nx; 02100 02101 if_e = data + (2 * (nobjects - total) 02102 + (total - j - 1)) * nx; 02103 02104 data = cpl_image_get_data_float(reduceds[pos_d]); 02105 02106 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02107 + (total - j - 1)) * nx; 02108 02109 ifdelta_e = data + (2 * (nobjects - total) 02110 + (total - j - 1)) * nx; 02111 02112 data = cpl_image_get_data_float(rerrors[pos]); 02113 02114 if_o_err = data 02115 + (2 * (nobjects - total) + nobjs_per_slit[p] 02116 + (total - j - 1)) * nx; 02117 02118 if_e_err = data + (2 * (nobjects - total) 02119 + (total - j - 1)) * nx; 02120 02121 data = cpl_image_get_data_float(rerrors[pos_d]); 02122 02123 ifdelta_o_err = data 02124 + (2 * (nobjects - total) + nobjs_per_slit[p] 02125 + (total - j - 1)) * nx; 02126 02127 ifdelta_e_err = data + (2 * (nobjects - total) 02128 + (total - j - 1)) * nx; 02129 02130 if (bagoo) { 02131 02132 char *signal_to_noise = getenv("SIGNAL_TO_NOISE" ); 02133 float s2n = 100.; 02134 char *min_s2n = getenv("MIN_S2N" ); 02135 int ms2n = 50; 02136 02137 if (signal_to_noise) 02138 s2n = atof(signal_to_noise); 02139 02140 if (min_s2n) 02141 ms2n = atoi(min_s2n); 02142 02143 /* 02144 * Check whether S/N is > s2n in more than ms2n pixels 02145 * (on first frame, on ordinary beam) 02146 */ 02147 02148 if (k == 0) { 02149 bright = 0; 02150 for (m = 0; m < nx; m++) { 02151 if (if_o_err[m] > 0.0) { 02152 if (if_o[m]/if_o_err[m] > s2n) { 02153 bright++; 02154 if (bright > ms2n) { 02155 break; 02156 } 02157 } 02158 } 02159 } 02160 } 02161 02162 if (bright > ms2n) { 02163 conta++; 02164 filename = cpl_sprintf("angle_%d_%d.dat", 02165 180*k-45, conta); 02166 file = fopen(filename, "w"); 02167 02168 fprintf(file, "%d\n", p + 2); 02169 02170 for (m = 0; m < nx; m++) { 02171 double lambda = startwavelength 02172 + dispersion * group * (0.5 + m); 02173 fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n", 02174 lambda, if_o[m], if_o_err[m], 02175 if_e[m], if_e_err[m]); 02176 } 02177 02178 fclose(file); 02179 cpl_free(filename); 02180 02181 filename = cpl_sprintf("angle_%d_%d.dat", 02182 180*k+45, conta); 02183 file = fopen(filename, "w"); 02184 02185 fprintf(file, "%d\n", p + 2); 02186 02187 for (m = 0; m < nx; m++) { 02188 double lambda = startwavelength 02189 + dispersion * group * (0.5 + m); 02190 fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n", 02191 lambda, ifdelta_o[m], ifdelta_o_err[m], 02192 ifdelta_e[m], ifdelta_e_err[m]); 02193 } 02194 02195 fclose(file); 02196 cpl_free(filename); 02197 } 02198 else { 02199 cpl_msg_info(recipe, 02200 "Extracted signal not written to " 02201 "ASCII (S/N > %.0f only in %d < %d " 02202 "bins)", s2n, bright, ms2n); 02203 } 02204 } // End of bagoo 02205 02206 for (m = 0; m < nx; m++) { 02207 02208 double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 : 02209 (if_o[m] - if_e[m] ) / 02210 (if_o[m] + if_e[m] ) - 02211 (ifdelta_o[m] - ifdelta_e[m]) / 02212 (ifdelta_o[m] + ifdelta_e[m]); 02213 02214 quantity = isfinite(quantity) ? quantity : 0.0; 02215 02216 /* PQ map computation */ 02217 ip_v[m] += quantity * 0.5 / (nscience / 2); 02218 02219 /* PQnull map computation */ 02220 if (nscience / 2 > 1) { 02221 if (k % 2) 02222 ip_vnull[m] += quantity * 0.5 / (nscience / 2); 02223 else 02224 ip_vnull[m] -= quantity * 0.5 / (nscience / 2); 02225 } 02226 02227 /* I map computation */ 02228 ip_i[m] += (if_o[m] + if_e[m] + 02229 ifdelta_o[m] + ifdelta_e[m]) / nscience; 02230 02231 /* Variance map computation */ 02232 ipierr[m] += (if_o_err[m] * if_o_err[m] 02233 + if_e_err[m] * if_e_err[m] 02234 + ifdelta_o_err[m] * ifdelta_o_err[m] 02235 + ifdelta_e_err[m] * ifdelta_e_err[m]) 02236 / nscience / nscience; 02237 02238 } 02239 } 02240 02241 /* Error map */ 02242 data = cpl_image_get_data_float(reduceds[0]); 02243 iff = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02244 02245 data = cpl_image_get_data_float(rerrors[0]); 02246 ierr = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02247 02248 for (m = 0; m < nx; m++) 02249 iperr[m] = iff[m] <= 0.0 ? 02250 0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2); 02251 02252 if (nscience / 2 > 1) { 02253 float * weights; 02254 float max, sum, sum2, imean; 02255 02256 int k; 02257 02258 /* QC on U NULL */ 02259 weights = cpl_malloc(sizeof(float) * nx); 02260 02261 max = 0.0; 02262 for (k = 0; k < nx; k++) { 02263 if (max < iff[k]) max = iff[k]; 02264 } 02265 02266 for (k = 0; k < nx; k++) { 02267 weights[k] = iff[k] < 0.0 ? 02268 0.0 : iff[k] * iff[k] / (max * max); 02269 } 02270 02271 sum = 0.0; 02272 sum2 = 0.0; 02273 for (k = 0; k < nx; k++) { 02274 sum += weights[k] * ip_vnull[k]; 02275 sum2 += weights[k]; 02276 } 02277 02278 cpl_free(weights); 02279 02280 imean = sum / sum2; 02281 02282 mean_vnull += (imean - mean_vnull) / (j + 1.0); 02283 } 02284 } 02285 02286 if (dfs_save_image(frameset, pv_im, reduced_v_tag, header, 02287 parlist, recipe, version)) 02288 fors_pmos_science_exit(NULL); 02289 02290 if (dfs_save_image(frameset, pi_im, reduced_i_tag, header, 02291 parlist, recipe, version)) 02292 fors_pmos_science_exit(NULL); 02293 02294 if (nscience / 2 > 1) { 02295 char *pipefile; 02296 char *keyname; 02297 cpl_propertylist *qheader; 02298 02299 qheader = dfs_load_header(frameset, science_tag, 0); 02300 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 02301 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 02302 cpl_propertylist_update_double(qheader, "CRVAL1", 02303 startwavelength + (dispersion * group)/2); 02304 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 02305 cpl_propertylist_update_double(qheader, "CD1_1", 02306 dispersion * group); 02307 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 02308 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 02309 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 02310 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 02311 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 02312 02313 if (qc) { 02314 fors_qc_start_group(qheader, "2.0", instrume); 02315 02316 /* 02317 * QC1 group header 02318 */ 02319 02320 if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag, 02321 "Product category", instrume)) 02322 fors_pmos_science_exit("Cannot write product category to " 02323 "QC log file"); 02324 02325 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 02326 "DPR type", instrume)) 02327 fors_pmos_science_exit("Missing keyword DPR TYPE in " 02328 "scientific frame header"); 02329 02330 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 02331 "Template", instrume)) 02332 fors_pmos_science_exit("Missing keyword TPL ID in " 02333 "scientific frame header"); 02334 02335 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 02336 "Grism name", instrume)) 02337 fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in " 02338 "scientific frame header"); 02339 02340 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 02341 "Grism identifier", instrume)) 02342 fors_pmos_science_exit("Missing keyword INS GRIS1 ID in " 02343 "scientific frame header"); 02344 02345 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 02346 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 02347 "Filter name", instrume); 02348 02349 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 02350 "Collimator name", instrume)) 02351 fors_pmos_science_exit("Missing keyword INS COLL NAME in " 02352 "scientific frame header"); 02353 02354 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 02355 "Chip identifier", instrume)) 02356 fors_pmos_science_exit("Missing keyword DET CHIP1 ID in " 02357 "scientific frame header"); 02358 02359 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 02360 "Archive name of input data", 02361 instrume)) 02362 fors_pmos_science_exit("Missing keyword ARCFILE in " 02363 "scientific frame header"); 02364 02365 pipefile = dfs_generate_filename_tfits(reduced_nul_v_tag); 02366 if (fors_qc_write_string("PIPEFILE", pipefile, 02367 "Pipeline product name", instrume)) 02368 fors_pmos_science_exit("Cannot write PIPEFILE to " 02369 "QC log file"); 02370 cpl_free(pipefile); pipefile = NULL; 02371 02372 02373 /* 02374 * QC1 parameters 02375 */ 02376 02377 keyname = "QC.NULL.V.MEAN"; 02378 02379 if (fors_qc_write_qc_double(qheader, mean_vnull, 02380 keyname, NULL, 02381 "Mean V null parameter", 02382 instrume)) { 02383 fors_pmos_science_exit("Cannot write mean Q null " 02384 "parameter to QC log file."); 02385 } 02386 02387 keyname = "QC.NANGLES"; 02388 02389 if (fors_qc_write_qc_int(qheader, nscience, 02390 keyname, NULL, 02391 "Number of processed plate angles", 02392 instrume)) { 02393 fors_pmos_science_exit("Cannot write number of processed " 02394 "plate angles."); 02395 } 02396 02397 fors_qc_end_group(); 02398 } 02399 02400 if (dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader, 02401 parlist, recipe, version)) 02402 fors_pmos_science_exit(NULL); 02403 02404 cpl_propertylist_delete(qheader); 02405 } 02406 02407 if (dfs_save_image(frameset, perr_im, reduced_error_v_tag, header, 02408 parlist, recipe, version)) 02409 fors_pmos_science_exit(NULL); 02410 02411 cpl_image_power(pierr_im, 0.5); 02412 02413 if (dfs_save_image(frameset, pierr_im, reduced_error_i_tag, header, 02414 parlist, recipe, version)) 02415 fors_pmos_science_exit(NULL); 02416 02417 cpl_image_delete(pv_im); 02418 cpl_image_delete(pvnull_im); 02419 cpl_image_delete(perr_im); 02420 cpl_image_delete(pi_im); 02421 cpl_image_delete(pierr_im); 02422 } 02423 else { /* Linear polarisation */ 02424 cpl_image *pq_im = NULL; 02425 cpl_image *pu_im = NULL; 02426 cpl_image *pl_im = NULL; 02427 cpl_image *pi_im = NULL; 02428 02429 cpl_image *pqnull_im = NULL; 02430 cpl_image *punull_im = NULL; 02431 02432 cpl_image *pqerr_im = NULL; 02433 cpl_image *puerr_im = NULL; 02434 cpl_image *plerr_im = NULL; 02435 cpl_image *pierr_im = NULL; 02436 02437 cpl_image *pang_im = NULL; 02438 cpl_image *pangerr_im = NULL; 02439 02440 double *p_q = NULL; 02441 double *p_u = NULL; 02442 double *p_l = NULL; 02443 double *p_i = NULL; 02444 02445 double *p_qnull = NULL; 02446 double *p_unull = NULL; 02447 02448 double *pqerr = NULL; 02449 double *puerr = NULL; 02450 double *plerr = NULL; 02451 double *pierr = NULL; 02452 02453 double *pang = NULL; 02454 double *pangerr = NULL; 02455 02456 int k, m; 02457 02458 cpl_image *correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE); 02459 double *correct = cpl_image_get_data_double(correct_im); 02460 02461 double mean_unull, mean_qnull; 02462 02463 int p = -1; 02464 int total = 0; 02465 02466 pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02467 pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02468 pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02469 pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02470 02471 pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02472 puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02473 plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02474 pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02475 02476 pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02477 pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02478 02479 p_q = cpl_image_get_data_double(pq_im); 02480 p_u = cpl_image_get_data_double(pu_im); 02481 p_l = cpl_image_get_data_double(pl_im); 02482 p_i = cpl_image_get_data_double(pi_im); 02483 02484 if (nscience / 4 > 1) { 02485 pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02486 punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE); 02487 02488 p_qnull = cpl_image_get_data_double(pqnull_im); 02489 p_unull = cpl_image_get_data_double(punull_im); 02490 } else { 02491 cpl_msg_warning(cpl_func, 02492 "Not enough pairs to compute null parameters"); 02493 } 02494 02495 pqerr = cpl_image_get_data_double(pqerr_im); 02496 puerr = cpl_image_get_data_double(puerr_im); 02497 plerr = cpl_image_get_data_double(plerr_im); 02498 pierr = cpl_image_get_data_double(pierr_im); 02499 02500 pang = cpl_image_get_data_double(pang_im); 02501 pangerr = cpl_image_get_data_double(pangerr_im); 02502 02503 if (chromatism) { 02504 cpl_table * chrotbl = 02505 dfs_load_table(frameset, chrom_table_tag, 1); 02506 02507 int nrow = cpl_table_get_nrow(chrotbl); 02508 float * lambda = cpl_table_get_data_float(chrotbl, "lambda"); 02509 float * theta = cpl_table_get_data_float(chrotbl, "eps_theta"); 02510 02511 for (j = 0; j < nx; j++) { 02512 double c_wave = startwavelength 02513 + (dispersion * group) / 2 02514 + j * dispersion * group; 02515 02516 int found = 0; 02517 02518 for (k = 0; k < nrow - 1; k++) { 02519 if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) { 02520 found = 1; 02521 break; 02522 } 02523 } 02524 02525 if (found) { 02526 correct[j] = (theta [k + 1] - theta [k]) / 02527 (lambda[k + 1] - lambda[k]) * 02528 (c_wave - lambda[k]) + theta[k]; 02529 correct[j] *= M_PI / 180; /* Radians */ 02530 } 02531 else if (j) 02532 correct[j] = correct[j-1]; 02533 else 02534 correct[j] = 0.0; 02535 } 02536 02537 cpl_table_delete(chrotbl); 02538 } 02539 02540 for (j = 0; j < nobjects; j++) { 02541 double *ip_q; 02542 double *ip_u; 02543 double *ip_l; 02544 double *ip_i; 02545 double *ipierr; 02546 double *ip_qnull; 02547 double *ip_unull; 02548 double *ipqerr; 02549 double *ipuerr; 02550 double *iplerr; 02551 double *ipang; 02552 double *ipangerr; 02553 02554 float *data; 02555 float *iffq; 02556 float *ierrq; 02557 float *iffu; 02558 float *ierru; 02559 02560 int pos, pos_d; 02561 02562 ip_q = p_q + (nobjects - 1 - j) * nx; 02563 ip_u = p_u + (nobjects - 1 - j) * nx; 02564 ip_l = p_l + (nobjects - 1 - j) * nx; 02565 ip_i = p_i + (nobjects - 1 - j) * nx; 02566 02567 if (nscience / 4 > 1) { 02568 ip_qnull = p_qnull + (nobjects - 1 - j) * nx; 02569 ip_unull = p_unull + (nobjects - 1 - j) * nx; 02570 } 02571 02572 ipqerr = pqerr + (nobjects - 1 - j) * nx; 02573 ipuerr = puerr + (nobjects - 1 - j) * nx; 02574 iplerr = plerr + (nobjects - 1 - j) * nx; 02575 ipierr = pierr + (nobjects - 1 - j) * nx; 02576 02577 ipang = pang + (nobjects - 1 - j) * nx; 02578 ipangerr = pangerr + (nobjects - 1 - j) * nx; 02579 02580 total = 0; 02581 for (i = 0; i < nslits; i += 2) { 02582 total += nobjs_per_slit[i]; 02583 if (total > j) { 02584 p = i; 02585 break; 02586 } 02587 } 02588 02589 for (k = 0; k < nscience / 4; k++) { 02590 float * if_o, * if_e, * ifdelta_o, * ifdelta_e; 02591 float * if_o_err, * if_e_err, * ifdelta_o_err, * ifdelta_e_err; 02592 02593 /* First P_Q */ 02594 02595 pos = fors_find_angle_pos(angles, nscience, 90 * k); 02596 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45); 02597 02598 data = cpl_image_get_data_float(reduceds[pos]); 02599 02600 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02601 + (total - j - 1)) * nx; 02602 02603 if_e = data + (2 * (nobjects - total) 02604 + (total - j - 1)) * nx; 02605 02606 data = cpl_image_get_data_float(reduceds[pos_d]); 02607 02608 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02609 + (total - j - 1)) * nx; 02610 02611 ifdelta_e = data + (2 * (nobjects - total) 02612 + (total - j - 1)) * nx; 02613 02614 data = cpl_image_get_data_float(rerrors[pos]); 02615 02616 if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02617 + (total - j - 1)) * nx; 02618 02619 if_e_err = data + (2 * (nobjects - total) 02620 + (total - j - 1)) * nx; 02621 02622 data = cpl_image_get_data_float(rerrors[pos_d]); 02623 02624 ifdelta_o_err = data + (2 * (nobjects - total) 02625 + nobjs_per_slit[p] + (total - j - 1)) * nx; 02626 02627 ifdelta_e_err = data + (2 * (nobjects - total) 02628 + (total - j - 1)) * nx; 02629 02630 for (m = 0; m < nx; m++) { 02631 02632 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 : 02633 (if_o[m] - if_e[m] ) / 02634 (if_o[m] + if_e[m] ) - 02635 (ifdelta_o[m] - ifdelta_e[m]) / 02636 (ifdelta_o[m] + ifdelta_e[m]); 02637 02638 quantity = isfinite(quantity) ? quantity : 0.0; 02639 02640 /* PQ map computation */ 02641 ip_q[m] += quantity * 0.5 / (nscience / 4); 02642 02643 /* PQnull map computation */ 02644 if (nscience / 4 > 1) { 02645 if (k % 2) 02646 ip_qnull[m] += quantity * 0.5 / (nscience / 4); 02647 else 02648 ip_qnull[m] -= quantity * 0.5 / (nscience / 4); 02649 } 02650 02651 /* I map computation */ 02652 ip_i[m] += (if_o[m] + if_e[m] + 02653 ifdelta_o[m] + ifdelta_e[m]) / nscience; 02654 02655 /* Variance map computation */ 02656 ipierr[m] += (if_o_err[m] * if_o_err[m] 02657 + if_e_err[m] * if_e_err[m] 02658 + ifdelta_o_err[m] * ifdelta_o_err[m] 02659 + ifdelta_e_err[m] * ifdelta_e_err[m]) 02660 / nscience / nscience; 02661 } 02662 02663 /* Now P_U */ 02664 02665 pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5); 02666 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5); 02667 02668 data = cpl_image_get_data_float(reduceds[pos]); 02669 02670 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02671 + (total - j - 1)) * nx; 02672 02673 if_e = data + (2 * (nobjects - total) 02674 + (total - j - 1)) * nx; 02675 02676 data = cpl_image_get_data_float(reduceds[pos_d]); 02677 02678 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02679 + (total - j - 1)) * nx; 02680 02681 ifdelta_e = data + (2 * (nobjects - total) 02682 + (total - j - 1)) * nx; 02683 02684 data = cpl_image_get_data_float(rerrors[pos]); 02685 02686 if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p] 02687 + (total - j - 1)) * nx; 02688 02689 if_e_err = data + (2 * (nobjects - total) 02690 + (total - j - 1)) * nx; 02691 02692 data = cpl_image_get_data_float(rerrors[pos_d]); 02693 02694 ifdelta_o_err = data + (2 * (nobjects - total) 02695 + nobjs_per_slit[p] + (total - j - 1)) * nx; 02696 02697 ifdelta_e_err = data + (2 * (nobjects - total) 02698 + (total - j - 1)) * nx; 02699 02700 for (m = 0; m < nx; m++) { 02701 02702 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 : 02703 (if_o[m] - if_e[m] ) / 02704 (if_o[m] + if_e[m] ) - 02705 (ifdelta_o[m] - ifdelta_e[m]) / 02706 (ifdelta_o[m] + ifdelta_e[m]); 02707 02708 quantity = isfinite(quantity) ? quantity : 0.0; 02709 02710 /* PU map computation */ 02711 ip_u[m] += quantity * 0.5 / (nscience / 4); 02712 02713 /* PUnull map computation */ 02714 if (nscience / 4 > 1) { 02715 if (k % 2) 02716 ip_unull[m] += quantity * 0.5 / (nscience / 4); 02717 else 02718 ip_unull[m] -= quantity * 0.5 / (nscience / 4); 02719 } 02720 02721 /* I map computation */ 02722 ip_i[m] += (if_o[m] + if_e[m] + 02723 ifdelta_o[m] + ifdelta_e[m]) / nscience; 02724 02725 /* Variance map computation */ 02726 ipierr[m] += (if_o_err[m] * if_o_err[m] 02727 + if_e_err[m] * if_e_err[m] 02728 + ifdelta_o_err[m] * ifdelta_o_err[m] 02729 + ifdelta_e_err[m] * ifdelta_e_err[m]) 02730 / nscience / nscience; 02731 } 02732 } 02733 02734 /* Error map */ 02735 02736 pos = fors_find_angle_pos(angles, nscience, 0.0); 02737 02738 data = cpl_image_get_data_float(reduceds[pos]); 02739 iffq = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02740 02741 data = cpl_image_get_data_float(rerrors[pos]); 02742 ierrq = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02743 02744 pos = fors_find_angle_pos(angles, nscience, 22.5); 02745 02746 data = cpl_image_get_data_float(reduceds[pos]); 02747 iffu = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02748 02749 data = cpl_image_get_data_float(rerrors[pos]); 02750 ierru = data + (2 * (nobjects - total) + (total - j - 1)) * nx; 02751 02752 for (m = 0; m < nx; m++) { 02753 02754 double radicand; 02755 02756 ipqerr[m] = iffq[m] <= 0.0 ? 02757 0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4); 02758 02759 ipuerr[m] = iffu[m] <= 0.0 ? 02760 0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4); 02761 02762 iplerr[m] = 0.5 * (ipqerr[m] + ipuerr[m]); 02763 02764 /* PL computation */ 02765 ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]); 02766 02767 /* P angle computation */ 02768 if (fabs(ip_q[m]) < 0.00001) { 02769 if (ip_u[m] > 0.0) { 02770 ipang[m] = 45.0; 02771 } 02772 else { 02773 ipang[m] = 135.0; 02774 } 02775 } 02776 else { 02777 ipang[m] = 0.5 * atan(ip_u[m] / ip_q[m]) * 180 / M_PI; 02778 if (ip_q[m] > 0.0) { 02779 if (ip_u[m] < 0.0) { 02780 ipang[m] += 180.; 02781 } 02782 } 02783 else { 02784 ipang[m] += 90.; 02785 } 02786 } 02787 02788 /* Error on the angle computation */ 02789 radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] + 02790 ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m]; 02791 02792 ipangerr[m] = (ip_l[m] == 0.0 ? 0.0 : 02793 sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI); 02794 02795 /* 02796 * This is a quick and dirty patch for FORS2 had the 02797 * Wolly mounted +180 with respect to FORS1. I must 02798 * hardcode it, because there is no such info in the 02799 * header. 02800 */ 02801 02802 if (instrume[4] == '2') { 02803 02804 double w_rotation = - wollaston * M_PI / 2; 02805 02806 ipang[m] -= w_rotation * 180 / M_PI; 02807 02808 ip_q[m] = ip_q[m] * cos(2 * w_rotation) 02809 + ip_u[m] * sin(2 * w_rotation); 02810 02811 ip_u[m] = ip_u[m] * cos(2 * w_rotation) 02812 - ip_q[m] * sin(2 * w_rotation); 02813 } 02814 02815 if (chromatism) { 02816 ipang[m] -= correct[m] * 180 / M_PI; 02817 02818 ip_q[m] = ip_q[m] * cos(2 * correct[m]) 02819 + ip_u[m] * sin(2 * correct[m]); 02820 02821 ip_u[m] = ip_u[m] * cos(2 * correct[m]) 02822 - ip_q[m] * sin(2 * correct[m]); 02823 } 02824 02825 if (ipang[m] < 0.0) 02826 ipang[m] += 180.; 02827 else if (ipang[m] >= 180.0) 02828 ipang[m] -= 180.; 02829 } 02830 02831 if (nscience / 4 > 1) { 02832 float * weights; 02833 float max, sum, sum2, imean; 02834 02835 int k; 02836 02837 /* QC on Q NULL */ 02838 weights = cpl_malloc(sizeof(float) * nx); 02839 02840 max = 0.0; 02841 for (k = 0; k < nx; k++) { 02842 if (max < iffq[k]) max = iffq[k]; 02843 } 02844 02845 for (k = 0; k < nx; k++) { 02846 weights[k] = iffq[k] < 0.0 ? 02847 0.0 : iffq[k] * iffq[k] / (max * max); 02848 } 02849 02850 sum = 0.0; 02851 sum2 = 0.0; 02852 for (k = 0; k < nx; k++) { 02853 sum += weights[k] * ip_qnull[k]; 02854 sum2 += weights[k]; 02855 } 02856 02857 cpl_free(weights); 02858 02859 imean = sum / sum2; 02860 02861 mean_qnull += (imean - mean_qnull) / (j + 1.0); 02862 02863 /* QC on U NULL */ 02864 weights = cpl_malloc(sizeof(float) * nx); 02865 02866 max = 0.0; 02867 for (k = 0; k < nx; k++) { 02868 if (max < iffu[k]) max = iffu[k]; 02869 } 02870 02871 for (k = 0; k < nx; k++) { 02872 weights[k] = iffu[k] < 0.0 ? 02873 0.0 : iffu[k] * iffu[k] / (max * max); 02874 } 02875 02876 sum = 0.0; 02877 sum2 = 0.0; 02878 for (k = 0; k < nx; k++) { 02879 sum += weights[k] * ip_unull[k]; 02880 sum2 += weights[k]; 02881 } 02882 02883 cpl_free(weights); 02884 02885 imean = sum / sum2; 02886 02887 mean_unull += (imean - mean_unull) / (j + 1.0); 02888 } 02889 } 02890 02891 cpl_image_delete(correct_im); 02892 02893 if (dfs_save_image(frameset, pq_im, reduced_q_tag, header, 02894 parlist, recipe, version)) 02895 fors_pmos_science_exit(NULL); 02896 02897 if (dfs_save_image(frameset, pu_im, reduced_u_tag, header, 02898 parlist, recipe, version)) 02899 fors_pmos_science_exit(NULL); 02900 02901 if (qc && standard) { 02902 cpl_table *polsta = dfs_load_table(frameset, std_pmos_table_tag, 1); 02903 cpl_propertylist *qheader = dfs_load_header(frameset, 02904 science_tag, 0); 02905 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 02906 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 02907 cpl_propertylist_update_double(qheader, "CRVAL1", 02908 startwavelength + (dispersion * group)/2); 02909 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 02910 cpl_propertylist_update_double(qheader, "CD1_1", 02911 dispersion * group); 02912 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 02913 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 02914 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 02915 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 02916 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 02917 02918 if (mos_check_polarisation(pq_im, pqerr_im, pu_im, puerr_im, 02919 startwavelength, dispersion, 1000., 02920 polsta, ra, dec, &filter, 02921 &polarised, 02922 &qc_pl, &qc_pl_err, 02923 &qc_angle, &qc_angle_err)) { 02924 cpl_msg_warning(cpl_func, "No QC can be computed"); 02925 } 02926 else { 02927 char *pipefile; 02928 char *keyname; 02929 char *text; 02930 char band[] = {' ', '\0'}; 02931 02932 fors_qc_start_group(qheader, "2.0", instrume); 02933 02934 /* 02935 * QC1 group header 02936 */ 02937 02938 if (fors_qc_write_string("PRO.CATG", reduced_l_tag, 02939 "Product category", instrume)) 02940 fors_pmos_science_exit("Cannot write product category to " 02941 "QC log file"); 02942 02943 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 02944 "DPR type", instrume)) 02945 fors_pmos_science_exit("Missing keyword DPR TYPE in " 02946 "scientific frame header"); 02947 02948 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 02949 "Template", instrume)) 02950 fors_pmos_science_exit("Missing keyword TPL ID in " 02951 "scientific frame header"); 02952 02953 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 02954 "Grism name", instrume)) 02955 fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in " 02956 "scientific frame header"); 02957 02958 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 02959 "Grism identifier", instrume)) 02960 fors_pmos_science_exit("Missing keyword INS GRIS1 ID in " 02961 "scientific frame header"); 02962 02963 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 02964 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 02965 "Filter name", instrume); 02966 02967 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 02968 "Collimator name", instrume)) 02969 fors_pmos_science_exit("Missing keyword INS COLL NAME in " 02970 "scientific frame header"); 02971 02972 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 02973 "Chip identifier", instrume)) 02974 fors_pmos_science_exit("Missing keyword DET CHIP1 ID in " 02975 "scientific frame header"); 02976 02977 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 02978 "Archive name of input data", 02979 instrume)) 02980 fors_pmos_science_exit("Missing keyword ARCFILE in " 02981 "scientific frame header"); 02982 02983 pipefile = dfs_generate_filename_tfits(reduced_nul_q_tag); 02984 if (fors_qc_write_string("PIPEFILE", pipefile, 02985 "Pipeline product name", instrume)) 02986 fors_pmos_science_exit("Cannot write PIPEFILE to " 02987 "QC log file"); 02988 cpl_free(pipefile); pipefile = NULL; 02989 02990 02991 /* 02992 * QC1 parameters 02993 */ 02994 02995 keyname = "QC.PMOS.BAND"; 02996 02997 band[0] = filter; 02998 if (fors_qc_write_qc_string(qheader, keyname, band, 02999 "Band where polarisation was " 03000 "measured", instrume)) { 03001 fors_pmos_science_exit("Cannot write QC.PMOS.BAND " 03002 "parameter to QC log file"); 03003 } 03004 03005 keyname = "QC.PMOS.POLARISED"; 03006 03007 if (fors_qc_write_qc_int(qheader, polarised, keyname, NULL, 03008 "Polarisation is expected (1 = yes, " 03009 "0 = no)", instrume)) { 03010 fors_pmos_science_exit("Cannot write QC.PMOS.POLARISED " 03011 "parameter to QC log file"); 03012 } 03013 03014 keyname = "QC.PMOS.L.OFFSET"; 03015 03016 if (polarised) 03017 text = "Linear polarisation relative offset"; 03018 else 03019 text = "Linear polarisation offset"; 03020 03021 if (fors_qc_write_qc_double(qheader, qc_pl, keyname, NULL, 03022 text, instrume)) { 03023 fors_pmos_science_exit("Cannot write linear polarisation " 03024 "offset to QC log file"); 03025 } 03026 03027 keyname = "QC.PMOS.L.OFFSETERR"; 03028 03029 if (fors_qc_write_qc_double(qheader, qc_pl_err, keyname, NULL, 03030 "Error on linear polarisation offset", 03031 instrume)) { 03032 fors_pmos_science_exit("Cannot write linear polarisation " 03033 "offset error to QC log file"); 03034 } 03035 03036 if (polarised) { 03037 keyname = "QC.PMOS.ANGLE.OFFSET"; 03038 03039 if (fors_qc_write_qc_double(qheader, qc_angle, keyname, NULL, 03040 "Polarisation angle offset", 03041 instrume)) { 03042 fors_pmos_science_exit("Cannot write polarisation " 03043 "angle offset to QC log file"); 03044 } 03045 03046 keyname = "QC.PMOS.ANGLE.OFFSETERR"; 03047 03048 if (fors_qc_write_qc_double(qheader, qc_angle_err, keyname, 03049 NULL, "Error on polarisation " 03050 "angle offset", instrume)) { 03051 fors_pmos_science_exit("Cannot write polarisation " 03052 "angle offset error to QC " 03053 "log file"); 03054 } 03055 } 03056 03057 fors_qc_end_group(); 03058 } 03059 03060 if (dfs_save_image(frameset, pl_im, reduced_l_tag, qheader, 03061 parlist, recipe, version)) 03062 fors_pmos_science_exit(NULL); 03063 03064 cpl_propertylist_delete(qheader); 03065 } 03066 else { 03067 if (dfs_save_image(frameset, pl_im, reduced_l_tag, header, 03068 parlist, recipe, version)) 03069 fors_pmos_science_exit(NULL); 03070 } 03071 03072 if (nscience / 4 > 1) { 03073 char *pipefile; 03074 char *keyname; 03075 cpl_propertylist *qheader = dfs_load_header(frameset, 03076 science_tag, 0); 03077 03078 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 03079 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 03080 cpl_propertylist_update_double(qheader, "CRVAL1", 03081 startwavelength + (dispersion * group)/2); 03082 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 03083 cpl_propertylist_update_double(qheader, "CD1_1", 03084 dispersion * group); 03085 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 03086 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 03087 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 03088 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 03089 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 03090 03091 if (qc) { 03092 fors_qc_start_group(qheader, "2.0", instrume); 03093 03094 /* 03095 * QC1 group header 03096 */ 03097 03098 if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag, 03099 "Product category", instrume)) 03100 fors_pmos_science_exit("Cannot write product category to " 03101 "QC log file"); 03102 03103 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 03104 "DPR type", instrume)) 03105 fors_pmos_science_exit("Missing keyword DPR TYPE in " 03106 "scientific frame header"); 03107 03108 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 03109 "Template", instrume)) 03110 fors_pmos_science_exit("Missing keyword TPL ID in " 03111 "scientific frame header"); 03112 03113 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 03114 "Grism name", instrume)) 03115 fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in " 03116 "scientific frame header"); 03117 03118 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 03119 "Grism identifier", instrume)) 03120 fors_pmos_science_exit("Missing keyword INS GRIS1 ID in " 03121 "scientific frame header"); 03122 03123 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 03124 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 03125 "Filter name", instrume); 03126 03127 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 03128 "Collimator name", instrume)) 03129 fors_pmos_science_exit("Missing keyword INS COLL NAME in " 03130 "scientific frame header"); 03131 03132 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 03133 "Chip identifier", instrume)) 03134 fors_pmos_science_exit("Missing keyword DET CHIP1 ID in " 03135 "scientific frame header"); 03136 03137 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 03138 "Archive name of input data", 03139 instrume)) 03140 fors_pmos_science_exit("Missing keyword ARCFILE in " 03141 "scientific frame header"); 03142 03143 pipefile = dfs_generate_filename_tfits(reduced_nul_q_tag); 03144 if (fors_qc_write_string("PIPEFILE", pipefile, 03145 "Pipeline product name", instrume)) 03146 fors_pmos_science_exit("Cannot write PIPEFILE to " 03147 "QC log file"); 03148 cpl_free(pipefile); pipefile = NULL; 03149 03150 03151 /* 03152 * QC1 parameters 03153 */ 03154 03155 keyname = "QC.NULL.Q.MEAN"; 03156 03157 if (fors_qc_write_qc_double(qheader, mean_qnull, 03158 keyname, NULL, 03159 "Mean Q null parameter", 03160 instrume)) { 03161 fors_pmos_science_exit("Cannot write mean Q null " 03162 "parameter to QC log file"); 03163 } 03164 03165 keyname = "QC.NANGLES"; 03166 03167 if (fors_qc_write_qc_int(qheader, nscience / 2, 03168 keyname, NULL, 03169 "Number of processed plate angles", 03170 instrume)) { 03171 fors_pmos_science_exit("Cannot write number of processed " 03172 "plate angles."); 03173 } 03174 03175 fors_qc_end_group(); 03176 } 03177 03178 if (dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader, 03179 parlist, recipe, version)) 03180 fors_pmos_science_exit(NULL); 03181 03182 cpl_propertylist_delete(qheader); 03183 03184 qheader = dfs_load_header(frameset, science_tag, 0); 03185 03186 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0); 03187 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0); 03188 cpl_propertylist_update_double(qheader, "CRVAL1", 03189 startwavelength + (dispersion * group)/2); 03190 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0); 03191 cpl_propertylist_update_double(qheader, "CD1_1", 03192 dispersion * group); 03193 cpl_propertylist_update_double(qheader, "CD1_2", 0.0); 03194 cpl_propertylist_update_double(qheader, "CD2_1", 0.0); 03195 cpl_propertylist_update_double(qheader, "CD2_2", 1.0); 03196 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR"); 03197 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL"); 03198 03199 if (qc) { 03200 fors_qc_start_group(qheader, "2.0", instrume); 03201 03202 /* 03203 * QC1 group header 03204 */ 03205 03206 if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag, 03207 "Product category", instrume)) 03208 fors_pmos_science_exit("Cannot write product category to " 03209 "QC log file"); 03210 03211 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL, 03212 "DPR type", instrume)) 03213 fors_pmos_science_exit("Missing keyword DPR TYPE in " 03214 "scientific frame header"); 03215 03216 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL, 03217 "Template", instrume)) 03218 fors_pmos_science_exit("Missing keyword TPL ID in " 03219 "scientific frame header"); 03220 03221 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL, 03222 "Grism name", instrume)) 03223 fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in " 03224 "scientific frame header"); 03225 03226 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL, 03227 "Grism identifier", instrume)) 03228 fors_pmos_science_exit("Missing keyword INS GRIS1 ID in " 03229 "scientific frame header"); 03230 03231 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME")) 03232 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL, 03233 "Filter name", instrume); 03234 03235 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL, 03236 "Collimator name", instrume)) 03237 fors_pmos_science_exit("Missing keyword INS COLL NAME in " 03238 "scientific frame header"); 03239 03240 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL, 03241 "Chip identifier", instrume)) 03242 fors_pmos_science_exit("Missing keyword DET CHIP1 ID in " 03243 "scientific frame header"); 03244 03245 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL, 03246 "Archive name of input data", 03247 instrume)) 03248 fors_pmos_science_exit("Missing keyword ARCFILE in " 03249 "scientific frame header"); 03250 03251 pipefile = dfs_generate_filename_tfits(reduced_nul_u_tag); 03252 if (fors_qc_write_string("PIPEFILE", pipefile, 03253 "Pipeline product name", instrume)) 03254 fors_pmos_science_exit("Cannot write PIPEFILE to " 03255 "QC log file"); 03256 cpl_free(pipefile); pipefile = NULL; 03257 03258 03259 /* 03260 * QC1 parameters 03261 */ 03262 03263 keyname = "QC.NULL.U.MEAN"; 03264 03265 if (fors_qc_write_qc_double(qheader, mean_unull, 03266 keyname, NULL, 03267 "Mean U null parameter", 03268 instrume)) { 03269 fors_pmos_science_exit("Cannot write mean U null " 03270 "parameter to QC log file"); 03271 } 03272 03273 keyname = "QC.NANGLES"; 03274 03275 if (fors_qc_write_qc_int(qheader, nscience / 2, 03276 keyname, NULL, 03277 "Number of processed plate angles", 03278 instrume)) { 03279 fors_pmos_science_exit("Cannot write number of processed " 03280 "plate angles."); 03281 } 03282 03283 fors_qc_end_group(); 03284 } 03285 03286 if (dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader, 03287 parlist, recipe, version)) 03288 fors_pmos_science_exit(NULL); 03289 03290 cpl_propertylist_delete(qheader); 03291 } 03292 03293 if (dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header, 03294 parlist, recipe, version)) 03295 fors_pmos_science_exit(NULL); 03296 03297 if (dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header, 03298 parlist, recipe, version)) 03299 fors_pmos_science_exit(NULL); 03300 03301 if (dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header, 03302 parlist, recipe, version)) 03303 fors_pmos_science_exit(NULL); 03304 03305 if (dfs_save_image(frameset, pang_im, reduced_angle_tag, header, 03306 parlist, recipe, version)) 03307 fors_pmos_science_exit(NULL); 03308 03309 if (dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag, 03310 header, parlist, recipe, version)) 03311 fors_pmos_science_exit(NULL); 03312 03313 if (dfs_save_image(frameset, pi_im, reduced_i_tag, 03314 header, parlist, recipe, version)) 03315 fors_pmos_science_exit(NULL); 03316 03317 cpl_image_power(pierr_im, 0.5); 03318 03319 if (dfs_save_image(frameset, pierr_im, reduced_error_i_tag, 03320 header, parlist, recipe, version)) 03321 fors_pmos_science_exit(NULL); 03322 03323 /* %%% */ 03324 03325 cpl_image_delete(pq_im); 03326 cpl_image_delete(pu_im); 03327 cpl_image_delete(pl_im); 03328 cpl_image_delete(pi_im); 03329 03330 cpl_image_delete(pqnull_im); 03331 cpl_image_delete(punull_im); 03332 03333 cpl_image_delete(pqerr_im); 03334 cpl_image_delete(puerr_im); 03335 cpl_image_delete(plerr_im); 03336 cpl_image_delete(pierr_im); 03337 cpl_image_delete(pang_im); 03338 cpl_image_delete(pangerr_im); 03339 } 03340 03341 cpl_propertylist_delete(header); 03342 03343 /* End of Stokes computation */ 03344 03345 for (j = 0; j < nscience; j++) { 03346 cpl_image_delete(reduceds[j]); 03347 cpl_image_delete(rerrors[j]); 03348 cpl_table_delete(slitss[j]); 03349 cpl_image_delete(mappeds[j]); 03350 } 03351 03352 cpl_free(reduceds); 03353 cpl_free(rerrors); 03354 cpl_free(slitss); 03355 cpl_free(mappeds); 03356 03357 cpl_free(instrume); instrume = NULL; 03358 03359 cpl_free(skylocalmaps); 03360 03361 cpl_free(nobjs_per_slit); 03362 03363 if (cpl_error_get_code()) { 03364 cpl_msg_error(cpl_error_get_where(), cpl_error_get_message()); 03365 fors_pmos_science_exit(NULL); 03366 } 03367 else 03368 return 0; 03369 } 03370 03371 /*----------------------------------------------------------------------------*/ 03382 /*----------------------------------------------------------------------------*/ 03383 static float * fors_check_angles(cpl_frameset * frameset, 03384 int pmos, const char *tag, int * circ) 03385 { 03386 float *angles = NULL; 03387 cpl_frame *c_frame = NULL; 03388 char *ret_id = NULL; 03389 03390 int i = 0; 03391 03392 angles = cpl_malloc(sizeof(float) * pmos); 03393 03394 for (c_frame = cpl_frameset_find(frameset, tag); 03395 c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) { 03396 03397 cpl_propertylist * header = 03398 cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0); 03399 03400 if (!ret_id) { 03401 ret_id = cpl_strdup(cpl_propertylist_get_string(header, 03402 "ESO INS OPTI4 ID")); 03403 03404 if (ret_id[1] != '5' && ret_id[1] != '4') { 03405 cpl_msg_error(cpl_func, 03406 "Unknown retarder plate id: %s", ret_id); 03407 return NULL; 03408 } 03409 } else { 03410 char * c_ret_id = (char *) 03411 cpl_propertylist_get_string(header, "ESO INS OPTI4 ID"); 03412 if (ret_id[1] != c_ret_id[1]) { 03413 cpl_msg_error(cpl_func, "Input frames are not from the same " 03414 "retarder plate"); 03415 return NULL; 03416 } 03417 } 03418 03419 if (ret_id[1] == '5') { /* Linear polarimetry */ 03420 if (cpl_propertylist_has(header, "ESO INS RETA2 ROT")) { 03421 angles[i] = (float)floor(2*cpl_propertylist_get_double(header, 03422 "ESO INS RETA2 ROT") + 0.5)/2; 03423 } 03424 else if (cpl_propertylist_has(header, "ESO INS RETA2 POSANG")) { 03425 if (cpl_propertylist_has(header, "ESO ADA POSANG")) { 03426 double reta2pos = cpl_propertylist_get_double(header, 03427 "ESO INS RETA2 POSANG"); 03428 double adapos = cpl_propertylist_get_double(header, 03429 "ESO ADA POSANG"); 03430 angles[i] = (float)floor(2*(reta2pos - adapos) + 0.5)/2; 03431 } 03432 else { 03433 cpl_msg_error(cpl_func, 03434 "ESO ADA POSANG not found in header"); 03435 return NULL; 03436 } 03437 } 03438 else { 03439 cpl_msg_error(cpl_func, "Neither ESO INS RETA2 ROT nor " 03440 "ESO INS RETA2 POSANG found in header"); 03441 return NULL; 03442 } 03443 *circ = 0; 03444 } else { /* Circular polarimetry */ 03445 if (cpl_propertylist_has(header, "ESO INS RETA4 ROT")) { 03446 angles[i] = (float)floor(2*cpl_propertylist_get_double(header, 03447 "ESO INS RETA4 ROT") + 0.5)/2; 03448 //Check if it makes sense. Change in all other places 03449 if (angles[i] < 0) 03450 angles[i] = angles[i] + 360; 03451 } 03452 else if (cpl_propertylist_has(header, "ESO INS RETA4 POSANG")) { 03453 if (cpl_propertylist_has(header, "ESO ADA POSANG")) { 03454 double reta4pos = cpl_propertylist_get_double(header, 03455 "ESO INS RETA4 POSANG"); 03456 double adapos = cpl_propertylist_get_double(header, 03457 "ESO ADA POSANG"); 03458 angles[i] = (float)floor(2*(reta4pos - adapos) + 0.5/2); 03459 } 03460 else { 03461 cpl_msg_error(cpl_func, 03462 "ESO ADA POSANG not found in header"); 03463 return NULL; 03464 } 03465 } 03466 else { 03467 cpl_msg_error(cpl_func, "Neither ESO INS RETA4 ROT nor " 03468 "ESO INS RETA4 POSANG found in header"); 03469 return NULL; 03470 } 03471 *circ = 1; 03472 } 03473 03474 cpl_propertylist_delete(header); 03475 i++; 03476 } 03477 03478 cpl_free(ret_id); 03479 03480 if (*circ) { 03481 if (pmos != 2 && pmos != 4) { 03482 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles " 03483 "found, but either 2 or 4 are required for " 03484 "circular polarization measurements!", pmos); 03485 return NULL; 03486 } 03487 } else { 03488 if (pmos != 4 && pmos != 8 && pmos != 16) { 03489 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles " 03490 "found, but either 4, 8, or 16 are required for " 03491 "linear polarization measurements!", pmos); 03492 return NULL; 03493 } 03494 } 03495 03496 /* Check completeness */ 03497 03498 if (*circ) { 03499 for (i = 0; i < pmos; i++) { 03500 if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) { 03501 const char *cangles; 03502 switch (pmos) { 03503 case 2: cangles = "-45.0, 45.0"; break; 03504 case 4: cangles = "-45.0, 45.0, 135.0, 225.0"; break; 03505 default: assert(0); 03506 } 03507 03508 cpl_msg_error(cpl_func, "Wrong angle configuration: missing " 03509 "angle %.2f. All angles %s must be provided.", 03510 angles[i], cangles); 03511 return NULL; 03512 } 03513 } 03514 } 03515 else { 03516 for (i = 0; i < pmos; i++) { 03517 if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) { 03518 const char *cangles; 03519 switch (pmos) { 03520 case 4: cangles = "0.0, 22.5, 45.0, 67.5"; break; 03521 case 8: cangles = "0.0, 22.5, 45.0, 67.5, " 03522 "90.0, 112.5, 135.0, 157.5"; break; 03523 case 16: cangles = "0.0, 22.5, 45.0, 67.5, " 03524 "90.0, 112.5, 135.0, 157.5, " 03525 "180.0, 202.5, 225.0, 247.5, " 03526 "270.0, 292.5, 315.0, 337.5"; break; 03527 default: assert(0); 03528 } 03529 03530 cpl_msg_error(cpl_func, "Wrong angle configuration: missing " 03531 "angle %.2f. All angles %s must be provided.", 03532 angles[i], cangles); 03533 return NULL; 03534 } 03535 } 03536 } 03537 03538 return angles; 03539 } 03540 03541 /*----------------------------------------------------------------------------*/ 03549 /*----------------------------------------------------------------------------*/ 03550 static int 03551 fors_find_angle_pos(float * angles, int nangles, float angle) 03552 { 03553 int i, match = 0; 03554 03555 for (i = 0; i < nangles; i++) { 03556 if (fabs(angles[i] - angle) < 1.0 || 03557 fabs(angles[i] - 360.0 - angle) < 1.0) { 03558 match = 1; 03559 break; 03560 } 03561 } 03562 03563 return match ? i : -1; 03564 } 03565