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