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