00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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 ((const char *)message != NULL) 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 ((const char *)message != NULL) 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
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
00252
00253
00254 recipe->parameters = cpl_parameterlist_new();
00255
00256
00257
00258
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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;
00674 double reference;
00675 double gain;
00676 double ron;
00677 int standard;
00678 int highres;
00679 int i, j;
00680 cpl_error_code error;
00681
00682 int * nobjs_per_slit;
00683 int nslits_out_det = 0;
00684
00685
00686 snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
00687
00688 cpl_msg_set_indentation(2);
00689
00690
00691
00692
00693
00694 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00695 cpl_msg_indent_more();
00696
00697 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00698 fors_pmos_extract_exit("Too many in input: GRISM_TABLE");
00699
00700 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00701
00702 dispersion = dfs_get_parameter_double(parlist,
00703 "fors.fors_pmos_extract.dispersion", grism_table);
00704
00705 if (dispersion <= 0.0)
00706 fors_pmos_extract_exit("Invalid resampling step");
00707
00708 skyalign = dfs_get_parameter_int(parlist,
00709 "fors.fors_pmos_extract.skyalign", NULL);
00710
00711 if (skyalign > 2)
00712 fors_pmos_extract_exit("Max polynomial degree for sky alignment is 2");
00713
00714 wcolumn = dfs_get_parameter_string(parlist,
00715 "fors.fors_pmos_extract.wcolumn", NULL);
00716
00717 startwavelength = dfs_get_parameter_double(parlist,
00718 "fors.fors_pmos_extract.startwavelength", grism_table);
00719 if (startwavelength < 3000.0 || startwavelength > 13000.0)
00720 fors_pmos_extract_exit("Invalid wavelength");
00721
00722 endwavelength = dfs_get_parameter_double(parlist,
00723 "fors.fors_pmos_extract.endwavelength", grism_table);
00724 if (endwavelength < 3000.0 || endwavelength > 13000.0)
00725 fors_pmos_extract_exit("Invalid wavelength");
00726
00727 if (endwavelength - startwavelength <= 0.0)
00728 fors_pmos_extract_exit("Invalid wavelength interval");
00729
00730 flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flux", NULL);
00731
00732 flatfield = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.flatfield",
00733 NULL);
00734
00735 skyglobal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skyglobal",
00736 NULL);
00737 skylocal = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skylocal",
00738 NULL);
00739 skymedian = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.skymedian",
00740 NULL);
00741
00742
00743
00744
00745
00746 chromatism =
00747 dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.chromatism",
00748 NULL);
00749
00750 if (skylocal && skyglobal)
00751 fors_pmos_extract_exit("Cannot apply both local and global sky subtraction");
00752
00753 if (skylocal && skymedian)
00754 fors_pmos_extract_exit("Cannot apply sky subtraction both on extracted "
00755 "and non-extracted spectra");
00756
00757 cosmics = dfs_get_parameter_bool(parlist,
00758 "fors.fors_pmos_extract.cosmics", NULL);
00759
00760 if (cosmics)
00761 if (!(skyglobal || skylocal))
00762 fors_pmos_extract_exit("Cosmic rays correction requires "
00763 "either skylocal=true or skyglobal=true");
00764
00765 slit_margin = dfs_get_parameter_int(parlist,
00766 "fors.fors_pmos_extract.slit_margin",
00767 NULL);
00768 if (slit_margin < 0)
00769 fors_pmos_extract_exit("Value must be zero or positive");
00770
00771 ext_radius = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_radius",
00772 NULL);
00773 if (ext_radius < 0)
00774 fors_pmos_extract_exit("Value must be zero or positive");
00775
00776 cont_radius = dfs_get_parameter_int(parlist,
00777 "fors.fors_pmos_extract.cont_radius",
00778 NULL);
00779 if (cont_radius < 0)
00780 fors_pmos_extract_exit("Value must be zero or positive");
00781
00782 ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_extract.ext_mode",
00783 NULL);
00784 if (ext_mode < 0 || ext_mode > 1)
00785 fors_pmos_extract_exit("Invalid object extraction mode");
00786
00787 time_normalise = dfs_get_parameter_bool(parlist,
00788 "fors.fors_pmos_extract.time_normalise", NULL);
00789
00790 check = dfs_get_parameter_bool(parlist, "fors.fors_pmos_extract.check", NULL);
00791 cpl_table_delete(grism_table); grism_table = NULL;
00792
00793 if (cpl_error_get_code())
00794 fors_pmos_extract_exit("Failure getting the configuration parameters");
00795
00796
00797
00798
00799
00800
00801 cpl_msg_indent_less();
00802 cpl_msg_info(recipe, "Check input set-of-frames:");
00803 cpl_msg_indent_more();
00804
00805 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00806 cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
00807
00808 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00809 cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
00810
00811 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00812 cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
00813
00814 standard = 0;
00815 pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS");
00816
00817 if (pmos == 0) {
00818 pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS");
00819 standard = 1;
00820 }
00821
00822 if (pmos == 0)
00823 fors_pmos_extract_exit("Missing input scientific frame");
00824
00825 angles = fors_check_angles(frameset, pmos,
00826 standard ? "STANDARD_PMOS" : "SCIENCE_PMOS",
00827 &circ);
00828 if (angles == NULL)
00829 fors_pmos_extract_exit("Polarization angles could not be read");
00830
00831 if (circ)
00832 chromatism = 0;
00833
00834
00835
00836 nscience = pmos;
00837
00838 reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00839 rerrors = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00840 slitss = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
00841 mappeds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00842 skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
00843
00844 if (pmos) {
00845 cpl_msg_info(recipe, "PMOS data found");
00846 if (standard) {
00847 science_tag = "STANDARD_PMOS";
00848 reduced_science_tag = "REDUCED_STD_PMOS";
00849 unmapped_science_tag = "UNMAPPED_STD_PMOS";
00850 mapped_science_tag = "MAPPED_STD_PMOS";
00851 mapped_science_sky_tag = "MAPPED_ALL_STD_PMOS";
00852 skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_PMOS";
00853 wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_PMOS";
00854 disp_coeff_sky_tag = "DISP_COEFF_STD_PMOS";
00855 mapped_sky_tag = "MAPPED_SKY_STD_PMOS";
00856 unmapped_sky_tag = "UNMAPPED_SKY_STD_PMOS";
00857 object_table_tag = "OBJECT_TABLE_STD_PMOS";
00858 object_table_pol_tag = "OBJECT_TABLE_POL_STD_PMOS";
00859 reduced_sky_tag = "REDUCED_SKY_STD_PMOS";
00860 reduced_error_tag = "REDUCED_ERROR_STD_PMOS";
00861 reduced_q_tag = "REDUCED_Q_STD_PMOS";
00862 reduced_u_tag = "REDUCED_U_STD_PMOS";
00863 reduced_v_tag = "REDUCED_V_STD_PMOS";
00864 reduced_l_tag = "REDUCED_L_STD_PMOS";
00865 reduced_error_q_tag = "REDUCED_ERROR_Q_STD_PMOS";
00866 reduced_error_u_tag = "REDUCED_ERROR_U_STD_PMOS";
00867 reduced_error_v_tag = "REDUCED_ERROR_V_STD_PMOS";
00868 reduced_error_l_tag = "REDUCED_ERROR_L_STD_PMOS";
00869 reduced_nul_q_tag = "REDUCED_NUL_Q_STD_PMOS";
00870 reduced_nul_u_tag = "REDUCED_NUL_U_STD_PMOS";
00871 reduced_nul_v_tag = "REDUCED_NUL_V_STD_PMOS";
00872 reduced_angle_tag = "REDUCED_ANGLE_STD_PMOS";
00873 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS";
00874 }
00875 else {
00876 science_tag = "SCIENCE_PMOS";
00877 reduced_science_tag = "REDUCED_SCI_PMOS";
00878 unmapped_science_tag = "UNMAPPED_SCI_PMOS";
00879 mapped_science_tag = "MAPPED_SCI_PMOS";
00880 mapped_science_sky_tag = "MAPPED_ALL_SCI_PMOS";
00881 skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_PMOS";
00882 wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_PMOS";
00883 disp_coeff_sky_tag = "DISP_COEFF_SCI_PMOS";
00884 mapped_sky_tag = "MAPPED_SKY_SCI_PMOS";
00885 unmapped_sky_tag = "UNMAPPED_SKY_SCI_PMOS";
00886 object_table_tag = "OBJECT_TABLE_SCI_PMOS";
00887 object_table_pol_tag = "OBJECT_TABLE_POL_SCI_PMOS";
00888 reduced_sky_tag = "REDUCED_SKY_SCI_PMOS";
00889 reduced_error_tag = "REDUCED_ERROR_SCI_PMOS";
00890 reduced_q_tag = "REDUCED_Q_SCI_PMOS";
00891 reduced_u_tag = "REDUCED_U_SCI_PMOS";
00892 reduced_v_tag = "REDUCED_V_SCI_PMOS";
00893 reduced_l_tag = "REDUCED_L_SCI_PMOS";
00894 reduced_error_q_tag = "REDUCED_ERROR_Q_SCI_PMOS";
00895 reduced_error_u_tag = "REDUCED_ERROR_U_SCI_PMOS";
00896 reduced_error_v_tag = "REDUCED_ERROR_V_SCI_PMOS";
00897 reduced_error_l_tag = "REDUCED_ERROR_L_SCI_PMOS";
00898 reduced_nul_q_tag = "REDUCED_NUL_Q_SCI_PMOS";
00899 reduced_nul_u_tag = "REDUCED_NUL_U_SCI_PMOS";
00900 reduced_nul_v_tag = "REDUCED_NUL_V_SCI_PMOS";
00901 reduced_angle_tag = "REDUCED_ANGLE_SCI_PMOS";
00902 reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS";
00903 }
00904
00905 master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS";
00906 global_sky_spectrum_tag = "GLOBAL_SKY_SPECTRUM_PMOS";
00907
00908 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
00909 master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_PMOS";
00910 }
00911 }
00912
00913 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
00914 fors_pmos_extract_exit("Missing required input: MASTER_BIAS");
00915
00916 if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
00917 fors_pmos_extract_exit("Too many in input: MASTER_BIAS");
00918
00919 if (skyalign >= 0)
00920 if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
00921 fors_pmos_extract_exit("Too many in input: MASTER_SKYLINECAT");
00922
00923 if (chromatism) {
00924 if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) {
00925 cpl_msg_error(recipe, "Missing required input: %s",
00926 chrom_table_tag);
00927 fors_pmos_extract_exit(NULL);
00928 }
00929
00930 if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) {
00931 cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag);
00932 fors_pmos_extract_exit(NULL);
00933 }
00934 }
00935
00936 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
00937 if (flatfield) {
00938 cpl_msg_error(recipe, "Too many in input: %s",
00939 master_norm_flat_tag);
00940 fors_pmos_extract_exit(NULL);
00941 }
00942 else {
00943 cpl_msg_warning(recipe, "%s in input are ignored, "
00944 "since flat field correction was not requested",
00945 master_norm_flat_tag);
00946 }
00947 }
00948
00949 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
00950 if (!flatfield) {
00951 cpl_msg_warning(recipe, "%s in input is ignored, "
00952 "since flat field correction was not requested",
00953 master_norm_flat_tag);
00954 }
00955 }
00956
00957 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
00958 if (flatfield) {
00959 cpl_msg_error(recipe, "Flat field correction was requested, "
00960 "but no %s are found in input",
00961 master_norm_flat_tag);
00962 fors_pmos_extract_exit(NULL);
00963 }
00964 }
00965
00966 if (cpl_frameset_count_tags(frameset, master_distortion_tag) == 0)
00967 fors_pmos_extract_exit("Missing required input: MASTER_DISTORTION_TABLE");
00968
00969 if (cpl_frameset_count_tags(frameset, master_distortion_tag) > 1)
00970 fors_pmos_extract_exit("Too many in input: MASTER_DISTORTION_TABLE");
00971
00972 global = dfs_load_table(frameset, master_distortion_tag, 1);
00973 if (global == NULL)
00974 fors_pmos_extract_exit("Cannot load master distortion table");
00975
00976 cpl_msg_indent_less();
00977
00978
00979
00980
00981
00982
00983 header = dfs_load_header(frameset, science_tag, 0);
00984
00985 if (header == NULL)
00986 fors_pmos_extract_exit("Cannot load scientific frame header");
00987
00988 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00989 if (instrume == NULL)
00990 fors_pmos_extract_exit("Missing keyword INSTRUME in scientific header");
00991 instrume = cpl_strdup(instrume);
00992
00993 if (instrume[4] == '1')
00994 snprintf(version, 80, "%s/%s", "fors1", VERSION);
00995 if (instrume[4] == '2')
00996 snprintf(version, 80, "%s/%s", "fors2", VERSION);
00997
00998 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00999
01000 if (cpl_error_get_code() != CPL_ERROR_NONE)
01001 fors_pmos_extract_exit("Missing keyword ESO INS GRIS1 WLEN in scientific "
01002 "frame header");
01003
01004 if (reference < 3000.0)
01005 reference *= 10;
01006
01007 if (reference < 3000.0 || reference > 13000.0) {
01008 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
01009 "keyword ESO INS GRIS1 WLEN in scientific frame header",
01010 reference);
01011 fors_pmos_extract_exit(NULL);
01012 }
01013
01014 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
01015
01016 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
01017
01018 if (cpl_error_get_code() != CPL_ERROR_NONE)
01019 fors_pmos_extract_exit("Missing keyword ESO DET WIN1 BINX in scientific "
01020 "frame header");
01021
01022 if (rebin != 1) {
01023 dispersion *= rebin;
01024 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
01025 "resampling step used is %f A/pixel", rebin,
01026 dispersion);
01027 }
01028
01029 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
01030
01031 if (cpl_error_get_code() != CPL_ERROR_NONE)
01032 fors_pmos_extract_exit("Missing keyword ESO DET OUT1 CONAD in scientific "
01033 "frame header");
01034
01035 cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
01036
01037 ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
01038
01039 if (cpl_error_get_code() != CPL_ERROR_NONE)
01040 fors_pmos_extract_exit("Missing keyword ESO DET OUT1 RON in scientific "
01041 "frame header");
01042
01043 ron /= gain;
01044
01045 cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
01046
01047 cpl_msg_info(recipe, "Load normalised flat field (if present)...");
01048 cpl_msg_indent_more();
01049
01050 if (flatfield) {
01051 norm_flat = dfs_load_image(frameset, master_norm_flat_tag,
01052 CPL_TYPE_FLOAT, 0, 1);
01053 }
01054
01055 cpl_msg_info(recipe, "Produce mask slit position table...");
01056
01057 maskslits = mos_load_slits_fors_pmos(header, &nslits_out_det);
01058
01059 if (skyalign >= 0) {
01060
01061 cpl_msg_indent_less();
01062 cpl_msg_info(recipe, "Load input sky line catalog...");
01063 cpl_msg_indent_more();
01064
01065 wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
01066
01067 if (wavelengths) {
01068
01069
01070
01071
01072 nlines = cpl_table_get_nrow(wavelengths);
01073
01074 if (nlines == 0)
01075 fors_pmos_extract_exit("Empty input sky line catalog");
01076
01077 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
01078 cpl_msg_error(recipe, "Missing column %s in input line "
01079 "catalog table", wcolumn);
01080 fors_pmos_extract_exit(NULL);
01081 }
01082
01083 line = cpl_malloc(nlines * sizeof(double));
01084
01085 for (i = 0; i < nlines; i++)
01086 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
01087
01088 cpl_table_delete(wavelengths); wavelengths = NULL;
01089
01090 lines = cpl_vector_wrap(nlines, line);
01091 }
01092 else {
01093 cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
01094 }
01095 }
01096
01097
01098 cpl_propertylist_delete(header); header = NULL;
01099
01100
01101
01102
01103
01104 for (j = 0; j < nscience; j++) {
01105 int k;
01106
01107 cpl_msg_indent_less();
01108 cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f "
01109 "(%d out of %d) ...",
01110 angles[j], j + 1, nscience);
01111 cpl_msg_indent_more();
01112
01113 cpl_msg_info(recipe, "Load scientific exposure...");
01114 cpl_msg_indent_more();
01115
01116
01117
01118
01119
01120
01121
01122 header = dfs_load_header(frameset, science_tag, 0);
01123
01124 for (k = 0; k < j; k ++) {
01125 cpl_propertylist_delete(header);
01126 header = dfs_load_header(frameset, NULL, 0);
01127 }
01128
01129 spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
01130
01131 for (k = 0; k < j; k ++) {
01132 cpl_image_delete(spectra);
01133 spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
01134 }
01135
01136 if (spectra == NULL)
01137 fors_pmos_extract_exit("Cannot load scientific frame");
01138
01139 if (header == NULL)
01140 fors_pmos_extract_exit("Cannot load scientific frame header");
01141
01142 alltime = cpl_propertylist_get_double(header, "EXPTIME");
01143
01144 if (cpl_error_get_code() != CPL_ERROR_NONE)
01145 fors_pmos_extract_exit("Missing keyword EXPTIME in scientific "
01146 "frame header");
01147
01148
01149
01150
01151 cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s",
01152 alltime);
01153
01154 cpl_msg_indent_less();
01155
01156
01157
01158
01159
01160 cpl_msg_info(recipe, "Remove the master bias...");
01161
01162 bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
01163
01164 if (bias == NULL)
01165 fors_pmos_extract_exit("Cannot load master bias");
01166
01167 overscans = mos_load_overscans_vimos(header, 1);
01168
01169 dummy = mos_remove_bias(spectra, bias, overscans);
01170 cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
01171 cpl_image_delete(bias); bias = NULL;
01172 cpl_table_delete(overscans); overscans = NULL;
01173
01174 if (spectra == NULL)
01175 fors_pmos_extract_exit("Cannot remove bias from scientific frame");
01176
01177 ccd_xsize = nx = cpl_image_get_size_x(spectra);
01178 ny = cpl_image_get_size_y(spectra);
01179
01180 if (flatfield) {
01181
01182 if (norm_flat) {
01183 cpl_msg_info(recipe, "Apply flat field correction...");
01184 if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
01185 cpl_msg_error(recipe, "Failure of flat field correction: %s",
01186 cpl_error_get_message());
01187 fors_pmos_extract_exit(NULL);
01188 }
01189 }
01190 else {
01191 cpl_msg_error(recipe, "Cannot load input %s for flat field "
01192 "correction", master_norm_flat_tag);
01193 fors_pmos_extract_exit(NULL);
01194 }
01195
01196 }
01197
01198
01199
01200
01201
01202 slits = mos_build_slit_location(global, maskslits, ny);
01203
01204 if (slits == NULL) {
01205 fors_pmos_extract_exit("Cannot load slits location table");
01206 } else {
01207 cpl_table_new_column(slits, "pair_id", CPL_TYPE_INT);
01208
01209 int m, null, size = cpl_table_get_nrow(slits);
01210
01211 for (m = 0; m < size; m++) {
01212 int slit_id = cpl_table_get(slits, "slit_id", m, &null);
01213
01214 int pair_id = slit_id % 2 ? slit_id + 1 : slit_id;
01215
01216 cpl_table_set(slits, "pair_id", m, pair_id);
01217 }
01218 }
01219
01220 cpl_msg_info(recipe, "Processing scientific spectra...");
01221
01222
01223
01224
01225
01226 polytraces = mos_build_curv_coeff(global, maskslits, slits);
01227 if (polytraces == NULL)
01228 fors_pmos_extract_exit("Cannot create spectral curvature table");
01229
01230
01231
01232
01233
01234
01235 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01236
01237 smapped = mos_spatial_calibration(spectra, slits, polytraces, reference,
01238 startwavelength, endwavelength,
01239 dispersion, flux, coordinate);
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 idscoeff = mos_build_disp_coeff(global, slits);
01251 if (idscoeff == NULL)
01252 fors_pmos_extract_exit("Cannot create wavelength calibration table");
01253
01254 rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
01255 endwavelength);
01256
01257 if (dispersion > 1.0)
01258 highres = 0;
01259 else
01260 highres = 1;
01261
01262 if (skyalign >= 0) {
01263 if (skyalign) {
01264 cpl_msg_info(recipe, "Align wavelength solution to reference "
01265 "skylines applying %d order residual fit...", skyalign);
01266 }
01267 else {
01268 cpl_msg_info(recipe, "Align wavelength solution to reference "
01269 "skylines applying median offset...");
01270 }
01271
01272 if (!j) {
01273 offsets = mos_wavelength_align(smapped, slits, reference,
01274 startwavelength, endwavelength,
01275 idscoeff, lines, highres,
01276 skyalign, rainbow, 4);
01277
01278 if (offsets) {
01279 if (standard)
01280 cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01281 "to reference sky lines may be unreliable in "
01282 "this case!");
01283
01284 if (dfs_save_table(frameset, offsets, skylines_offsets_tag,
01285 NULL, parlist, recipe, version)) {
01286 fors_pmos_extract_exit(NULL);
01287 }
01288
01289 } else {
01290 cpl_msg_warning(recipe, "Alignment of the wavelength solution "
01291 "to reference sky lines could not be done!");
01292 skyalign = -1;
01293 }
01294 }
01295
01296
01297 }
01298
01299 wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
01300 polytraces, reference,
01301 startwavelength, endwavelength,
01302 dispersion);
01303
01304
01305 cpl_image_delete(rainbow); rainbow = NULL;
01306 cpl_image_delete(coordinate); coordinate = NULL;
01307
01308
01309
01310
01311
01312
01313 mapped_sky = mos_wavelength_calibration(smapped, reference,
01314 startwavelength, endwavelength,
01315 dispersion, idscoeff, flux);
01316
01317 if (!j) {
01318 cpl_msg_indent_less();
01319 cpl_msg_info(recipe, "Check applied wavelength against skylines...");
01320 cpl_msg_indent_more();
01321
01322 mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength,
01323 dispersion, 6, highres);
01324
01325
01326 cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
01327
01328 mean_rms = cpl_table_get_column_mean(idscoeff, "error");
01329
01330 cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
01331 mean_rms, mean_rms * dispersion);
01332 }
01333
01334 save_header = cpl_propertylist_duplicate(header);
01335
01336 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01337 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01338 cpl_propertylist_update_double(header, "CRVAL1",
01339 startwavelength + dispersion/2);
01340 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01341
01342
01343 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01344 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01345 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01346 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01347 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01348 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01349
01350 if (time_normalise) {
01351 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
01352 if (!j) {
01353 if(dfs_save_image_null(frameset, parlist,
01354 mapped_science_sky_tag,
01355 recipe, version)) {
01356 fors_pmos_extract_exit(NULL);
01357 }
01358 }
01359 if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) {
01360 fors_pmos_extract_exit(NULL);
01361 }
01362 cpl_image_delete(dummy); dummy = NULL;
01363 }
01364 else {
01365
01366 if (!j) {
01367 if(dfs_save_image_null(frameset, parlist,
01368 mapped_science_sky_tag,
01369 recipe, version)) {
01370 fors_pmos_extract_exit(NULL);
01371 }
01372 }
01373
01374 if (dfs_save_image_ext(mapped_sky,
01375 mapped_science_sky_tag, header)) {
01376 fors_pmos_extract_exit(NULL);
01377 }
01378
01379 }
01380
01381
01382 if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
01383 cpl_image_delete(mapped_sky); mapped_sky = NULL;
01384 }
01385
01386 if (skyglobal || skylocal) {
01387
01388 cpl_msg_indent_less();
01389
01390 if (skyglobal) {
01391 cpl_msg_info(recipe, "Global sky determination...");
01392 cpl_msg_indent_more();
01393 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01394
01395 sky = mos_sky_map_super(spectra, wavemap, dispersion,
01396 2.0, 50, skymap);
01397
01398 if (sky) {
01399 cpl_image_subtract(spectra, skymap);
01400 }
01401 else {
01402 cpl_image_delete(skymap); skymap = NULL;
01403 }
01404 }
01405 else {
01406 cpl_msg_info(recipe, "Local sky determination...");
01407 cpl_msg_indent_more();
01408 skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
01409 startwavelength, endwavelength, dispersion);
01410 }
01411
01412 if (skymap) {
01413 if (skyglobal) {
01414 if (time_normalise)
01415 cpl_table_divide_scalar(sky, "sky", alltime);
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434 if (!j) {
01435 if(dfs_save_image_null(frameset, parlist,
01436 global_sky_spectrum_tag,
01437 recipe, version)) {
01438 fors_pmos_extract_exit(NULL);
01439 }
01440 }
01441
01442 if (dfs_save_table_ext(sky, global_sky_spectrum_tag,
01443 NULL)) {
01444 fors_pmos_extract_exit(NULL);
01445 }
01446
01447
01448 cpl_table_delete(sky); sky = NULL;
01449 }
01450
01451
01452
01453 if (time_normalise)
01454 cpl_image_divide_scalar(skymap, alltime);
01455
01456 if (!j) {
01457 if(dfs_save_image_null(frameset, parlist,
01458 unmapped_sky_tag,
01459 recipe, version)) {
01460 fors_pmos_extract_exit(NULL);
01461 }
01462 }
01463
01464 if (dfs_save_image_ext(skymap, unmapped_sky_tag,
01465 save_header)) {
01466 fors_pmos_extract_exit(NULL);
01467 }
01468
01469 cpl_image_delete(skymap); skymap = NULL;
01470
01471 if (!j) {
01472 if(dfs_save_image_null(frameset, parlist,
01473 unmapped_science_tag,
01474 recipe, version)) {
01475 fors_pmos_extract_exit(NULL);
01476 }
01477 }
01478
01479 if (dfs_save_image_ext(spectra, unmapped_science_tag,
01480 save_header)) {
01481 fors_pmos_extract_exit(NULL);
01482 }
01483
01484
01485
01486 if (cosmics) {
01487 cpl_msg_info(recipe, "Removing cosmic rays...");
01488 mos_clean_cosmics(spectra, gain, -1., -1.);
01489 }
01490
01491
01492
01493
01494
01495
01496 cpl_image_delete(smapped); smapped = NULL;
01497
01498 smapped = mos_spatial_calibration(spectra, slits, polytraces,
01499 reference, startwavelength,
01500 endwavelength, dispersion,
01501 flux, NULL);
01502 }
01503 else {
01504 cpl_msg_warning(recipe, "Sky subtraction failure");
01505 if (cosmics)
01506 cpl_msg_warning(recipe, "Cosmic rays removal not performed!");
01507 cosmics = skylocal = skyglobal = 0;
01508 }
01509 }
01510
01511 cpl_image_delete(spectra); spectra = NULL;
01512 cpl_table_delete(polytraces); polytraces = NULL;
01513
01514 if (skyalign >= 0) {
01515 save_header = dfs_load_header(frameset, science_tag, 0);
01516
01517 if (!j) {
01518 if(dfs_save_image_null(frameset, parlist,
01519 wavelength_map_sky_tag,
01520 recipe, version)) {
01521 fors_pmos_extract_exit(NULL);
01522 }
01523 }
01524
01525 if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag,
01526 save_header)) {
01527 fors_pmos_extract_exit(NULL);
01528 }
01529
01530
01531 }
01532
01533 cpl_image_delete(wavemap); wavemap = NULL;
01534
01535 mapped = mos_wavelength_calibration(smapped, reference,
01536 startwavelength, endwavelength,
01537 dispersion, idscoeff, flux);
01538
01539 cpl_image_delete(smapped); smapped = NULL;
01540
01541 if (skyalign >= 0) {
01542 if (!j) {
01543 if (dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag,
01544 NULL, parlist, recipe, version)) {
01545 fors_pmos_extract_exit(NULL);
01546 }
01547 }
01548 }
01549
01550
01551 if (skymedian) {
01552 cpl_msg_indent_less();
01553 cpl_msg_info(recipe, "Local sky determination...");
01554 cpl_msg_indent_more();
01555
01556
01557
01558 skylocalmap = mos_sky_local_old(mapped, slits);
01559 cpl_image_subtract(mapped, skylocalmap);
01560
01561
01562
01563
01564
01565 cpl_image_delete(skylocalmap); skylocalmap = NULL;
01566 }
01567
01568
01569 if (skyglobal || skymedian || skylocal) {
01570
01571 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
01572
01573 cpl_image_delete(mapped_sky); mapped_sky = NULL;
01574
01575 if (time_normalise) {
01576 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
01577
01578 if (!j) {
01579 if(dfs_save_image_null(frameset, parlist,
01580 mapped_sky_tag,
01581 recipe, version)) {
01582 fors_pmos_extract_exit(NULL);
01583 }
01584 }
01585
01586 if (dfs_save_image_ext(dummy, mapped_sky_tag,
01587 header)) {
01588 fors_pmos_extract_exit(NULL);
01589 }
01590
01591 cpl_image_delete(dummy); dummy = NULL;
01592 }
01593 else {
01594 if (!j) {
01595 if(dfs_save_image_null(frameset, parlist,
01596 mapped_sky_tag,
01597 recipe, version)) {
01598 fors_pmos_extract_exit(NULL);
01599 }
01600 }
01601
01602 if (dfs_save_image_ext(skylocalmap, mapped_sky_tag,
01603 header)) {
01604 fors_pmos_extract_exit(NULL);
01605 }
01606 }
01607
01608 skylocalmaps[j] = skylocalmap;
01609
01610 cpl_msg_indent_less();
01611 cpl_msg_info(recipe, "Object detection...");
01612 cpl_msg_indent_more();
01613
01614 if (!j)
01615 origslits = cpl_table_duplicate(slits);
01616
01617 if (cosmics || nscience > 1) {
01618 dummy = mos_detect_objects(mapped, slits, slit_margin, ext_radius,
01619 cont_radius);
01620 }
01621 else {
01622 mapped_cleaned = cpl_image_duplicate(mapped);
01623 mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
01624 dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin,
01625 ext_radius, cont_radius);
01626
01627 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
01628 }
01629
01630 cpl_image_delete(dummy); dummy = NULL;
01631
01632 if (check) {
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649 if (!j) {
01650 if(dfs_save_image_null(frameset, parlist,
01651 object_table_tag,
01652 recipe, version)) {
01653 fors_pmos_extract_exit(NULL);
01654 }
01655 }
01656
01657 if (dfs_save_table_ext(slits, object_table_tag, NULL)) {
01658 fors_pmos_extract_exit(NULL);
01659 }
01660 }
01661 }
01662
01663 slitss[j] = slits;
01664 mappeds[j] = mapped;
01665
01666 cpl_msg_indent_less();
01667
01668 cpl_propertylist_delete(header); header = NULL;
01669 cpl_propertylist_delete(save_header); save_header = NULL;
01670
01671 cpl_table_delete(idscoeff); idscoeff = NULL;
01672 }
01673
01674 cpl_table_delete(offsets); offsets = NULL;
01675
01676 cpl_image_delete(norm_flat); norm_flat = NULL;
01677 cpl_vector_delete(lines); lines = NULL;
01678
01679 cpl_table_delete(maskslits); maskslits = NULL;
01680
01681
01682 cpl_msg_indent_less();
01683 cpl_msg_info(recipe,
01684 "Check object detection in both beams for all angles...");
01685 cpl_msg_indent_more();
01686
01687
01688
01689 error = mos_object_intersect(slitss, origslits, nscience, 5.0);
01690 if (error == CPL_ERROR_DATA_NOT_FOUND) {
01691 cpl_msg_warning(recipe, "No objects found: no Stokes "
01692 "parameters to compute!");
01693 for (j = 0; j < nscience; j++)
01694 cpl_table_delete(slitss[j]);
01695 cpl_free(slitss);
01696 cpl_table_delete(origslits);
01697 return 0;
01698 } else if (error) {
01699 fors_pmos_extract_exit("Problem in polarimetric object selection");
01700 }
01701
01702 if (dfs_save_table(frameset, origslits, object_table_pol_tag,
01703 NULL, parlist, recipe, version)) {
01704 fors_pmos_extract_exit(NULL);
01705 }
01706
01707 nobjs_per_slit = fors_get_nobjs_perslit(origslits);
01708
01709 cpl_msg_indent_less();
01710 cpl_msg_info(recipe, "Object extraction...");
01711 cpl_msg_indent_more();
01712
01713 for (j = 0; j < nscience; j++) {
01714 int k;
01715
01716 header = dfs_load_header(frameset, science_tag, 0);
01717
01718 for (k = 0; k < j; k ++) {
01719 cpl_propertylist_delete(header);
01720 header = dfs_load_header(frameset, NULL, 0);
01721 }
01722
01723 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01724 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01725 cpl_propertylist_update_double(header, "CRVAL1",
01726 startwavelength + dispersion/2);
01727 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01728
01729
01730 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01731 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01732 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01733 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01734 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01735 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01736
01737 if (skyglobal || skymedian || skylocal) {
01738
01739 cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...",
01740 angles[j], j + 1, nscience);
01741
01742 images = mos_extract_objects(mappeds[j], NULL, skylocalmaps[j],
01743 origslits,
01744 ext_mode, ron, gain, 1);
01745
01746 cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
01747
01748 if (images) {
01749 if (time_normalise)
01750 cpl_image_divide_scalar(images[0], alltime);
01751
01752 if (!j) {
01753 if(dfs_save_image_null(frameset, parlist,
01754 reduced_science_tag,
01755 recipe, version)) {
01756 fors_pmos_extract_exit(NULL);
01757 }
01758 }
01759
01760 if (dfs_save_image_ext(images[0], reduced_science_tag,
01761 header)) {
01762 fors_pmos_extract_exit(NULL);
01763 }
01764
01765 reduceds[j] = images[0];
01766
01767
01768 if (time_normalise)
01769 cpl_image_divide_scalar(images[1], alltime);
01770
01771 if (!j) {
01772 if(dfs_save_image_null(frameset, parlist,
01773 reduced_sky_tag,
01774 recipe, version)) {
01775 fors_pmos_extract_exit(NULL);
01776 }
01777 }
01778
01779 if (dfs_save_image_ext(images[1], reduced_sky_tag,
01780 header)) {
01781 fors_pmos_extract_exit(NULL);
01782 }
01783 cpl_image_delete(images[1]);
01784
01785 if (time_normalise)
01786 cpl_image_divide_scalar(images[2], alltime);
01787
01788 if (!j) {
01789 if(dfs_save_image_null(frameset, parlist,
01790 reduced_error_tag,
01791 recipe, version)) {
01792 fors_pmos_extract_exit(NULL);
01793 }
01794 }
01795
01796 if (dfs_save_image_ext(images[2], reduced_error_tag,
01797 header)) {
01798 fors_pmos_extract_exit(NULL);
01799 }
01800
01801 rerrors[j] = images[2];
01802
01803
01804 cpl_free(images);
01805 }
01806 else {
01807 cpl_msg_warning(recipe, "No objects found: the products "
01808 "%s, %s, and %s are not created",
01809 reduced_science_tag, reduced_sky_tag,
01810 reduced_error_tag);
01811 }
01812
01813 }
01814
01815
01816
01817
01818
01819
01820 if (skyglobal || skymedian || skylocal) {
01821 if (time_normalise)
01822 cpl_image_divide_scalar(mappeds[j], alltime);
01823
01824 if (!j) {
01825 if(dfs_save_image_null(frameset, parlist,
01826 mapped_science_tag,
01827 recipe, version)) {
01828 fors_pmos_extract_exit(NULL);
01829 }
01830 }
01831
01832 if (dfs_save_image_ext(mappeds[j], mapped_science_tag,
01833 header)) {
01834 fors_pmos_extract_exit(NULL);
01835 }
01836 }
01837
01838 cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
01839 cpl_propertylist_delete(header); header = NULL;
01840
01841 }
01842
01843 cpl_table_delete(origslits);
01844
01845
01846
01847 nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
01848 nx = cpl_image_get_size_x(reduceds[0]);
01849
01850 header = cpl_propertylist_new();
01851 cpl_propertylist_update_double(header, "CRPIX1", 1.0);
01852 cpl_propertylist_update_double(header, "CRPIX2", 1.0);
01853 cpl_propertylist_update_double(header, "CRVAL1",
01854 startwavelength + dispersion/2);
01855 cpl_propertylist_update_double(header, "CRVAL2", 1.0);
01856
01857
01858 cpl_propertylist_update_double(header, "CD1_1", dispersion);
01859 cpl_propertylist_update_double(header, "CD1_2", 0.0);
01860 cpl_propertylist_update_double(header, "CD2_1", 0.0);
01861 cpl_propertylist_update_double(header, "CD2_2", 1.0);
01862 cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
01863 cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
01864
01865 if (circ) {
01866
01867 cpl_image *pv_im = NULL;
01868 cpl_image *pvnull_im = NULL;
01869 cpl_image *perr_im = NULL;
01870
01871 double *p_v = NULL;
01872 double *p_vnull = NULL;
01873 double *perr = NULL;
01874
01875 double mean_vnull;
01876
01877 int p = -1;
01878 int total = 0;
01879
01880 pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01881 perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01882
01883 p_v = cpl_image_get_data_double(pv_im);
01884 perr = cpl_image_get_data_double(perr_im);
01885
01886 if (nscience / 2 > 1) {
01887 pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
01888 p_vnull = cpl_image_get_data_double(pvnull_im);
01889 }
01890
01891 for (j = 0; j < nobjects; j++) {
01892 int k, m;
01893
01894 double * ip_v,
01895 * ip_vnull, * iperr;
01896
01897 float * data;
01898 float * iff, * ierr;
01899
01900 ip_v = p_v + (nobjects - 1 - j) * nx;
01901
01902 if (nscience / 2 > 1)
01903 ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
01904
01905 iperr = perr + (nobjects - 1 - j) * nx;
01906
01907 while (total < j + 1) {
01908 p++;
01909 total += nobjs_per_slit[p];
01910 }
01911
01912 for (k = 0; k < nscience / 2; k++) {
01913 float * if_o, * if_e, * ifdelta_o, * ifdelta_e;
01914
01915 int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45);
01916 int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
01917
01918 data = cpl_image_get_data_float(reduceds[pos]);
01919
01920 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
01921 + (total - j - 1)) * nx;
01922
01923 if_e = data + (2 * (nobjects - total)
01924 + (total - j - 1)) * nx;
01925
01926
01927
01928
01929 data = cpl_image_get_data_float(reduceds[pos_d]);
01930
01931 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
01932 + (total - j - 1)) * nx;
01933
01934 ifdelta_e = data + (2 * (nobjects - total)
01935 + (total - j - 1)) * nx;
01936
01937
01938
01939
01940 for (m = 0; m < nx; m++) {
01941
01942 double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
01943 (if_o[m] - if_e[m] ) /
01944 (if_o[m] + if_e[m] ) -
01945 (ifdelta_o[m] - ifdelta_e[m]) /
01946 (ifdelta_o[m] + ifdelta_e[m]);
01947
01948 quantity = isfinite(quantity) ? quantity : 0.0;
01949
01950
01951 ip_v[m] += quantity * 0.5 / (nscience / 2);
01952
01953
01954 if (nscience / 2 > 1) {
01955 if (k % 2)
01956 ip_vnull[m] += quantity * 0.5 / (nscience / 2);
01957 else
01958 ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
01959 }
01960 }
01961 }
01962
01963
01964 data = cpl_image_get_data_float(reduceds[0]);
01965 iff = data + 2 * (nobjects - 1 - j) * nx;
01966
01967 data = cpl_image_get_data_float(rerrors[0]);
01968 ierr = data + 2 * (nobjects - 1 - j) * nx;
01969
01970 for (m = 0; m < nx; m++)
01971 iperr[m] = iff[m] <= 0.0 ?
01972 0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
01973
01974 if (nscience / 2 > 1) {
01975 float * weights;
01976 float max, sum, sum2, imean;
01977
01978 int k;
01979
01980
01981 weights = cpl_malloc(sizeof(float) * nx);
01982
01983 max = 0.0;
01984 for (k = 0; k < nx; k++) {
01985 if (max < iff[k]) max = iff[k];
01986 }
01987
01988 for (k = 0; k < nx; k++) {
01989 weights[k] = iff[k] < 0.0 ?
01990 0.0 : iff[k] * iff[k] / (max * max);
01991 }
01992
01993 sum = 0.0;
01994 sum2 = 0.0;
01995 for (k = 0; k < nx; k++) {
01996 sum += weights[k] * ip_vnull[k];
01997 sum2 += weights[k];
01998 }
01999
02000 cpl_free(weights);
02001
02002 imean = sum / sum2;
02003
02004 mean_vnull += (imean - mean_vnull) / (j + 1.0);
02005 }
02006 }
02007
02008 if (dfs_save_image(frameset, pv_im, reduced_v_tag, header,
02009 parlist, recipe, version))
02010 fors_pmos_extract_exit(NULL);
02011
02012 if (nscience / 2 > 1) {
02013 char * pipefile, * keyname;
02014 cpl_propertylist * qheader = dfs_load_header(frameset, science_tag, 0);
02015
02016 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02017 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02018 cpl_propertylist_update_double(qheader, "CRVAL1",
02019 startwavelength + dispersion/2);
02020 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02021
02022
02023 cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02024 cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02025 cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02026 cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02027 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02028 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02029
02030 fors_qc_start_group(qheader, "2.0", instrume);
02031
02032
02033
02034
02035
02036 if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag,
02037 "Product category", instrume))
02038 fors_pmos_extract_exit("Cannot write product category to "
02039 "QC log file");
02040
02041 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02042 "DPR type", instrume))
02043 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02044 "lamp header");
02045
02046 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02047 "Template", instrume))
02048 fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02049 "lamp header");
02050
02051 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02052 "Grism name", instrume))
02053 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02054 "lamp header");
02055
02056 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02057 "Grism identifier", instrume))
02058 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02059 "lamp header");
02060
02061 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02062 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02063 "Filter name", instrume);
02064
02065 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02066 "Collimator name", instrume))
02067 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02068 "lamp header");
02069
02070 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02071 "Chip identifier", instrume))
02072 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02073 "lamp header");
02074
02075 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02076 "Archive name of input data",
02077 instrume))
02078 fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02079 "lamp header");
02080
02081 pipefile = dfs_generate_filename(reduced_nul_v_tag);
02082 if (fors_qc_write_string("PIPEFILE", pipefile,
02083 "Pipeline product name", instrume))
02084 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02085 cpl_free(pipefile); pipefile = NULL;
02086
02087
02088
02089
02090
02091
02092 keyname = "QC.NULL.V.MEAN";
02093
02094 if (fors_qc_write_qc_double(qheader, mean_vnull,
02095 keyname, NULL,
02096 "Mean V null parameter",
02097 instrume)) {
02098 fors_pmos_extract_exit("Cannot write mean Q null parameter "
02099 "to QC log file");
02100 }
02101
02102 fors_qc_end_group();
02103
02104 if (dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader,
02105 parlist, recipe, version))
02106 fors_pmos_extract_exit(NULL);
02107
02108 cpl_propertylist_delete(qheader);
02109 }
02110
02111 if (dfs_save_image(frameset, perr_im, reduced_error_v_tag, header,
02112 parlist, recipe, version))
02113 fors_pmos_extract_exit(NULL);
02114
02115 cpl_image_delete(pv_im);
02116 cpl_image_delete(pvnull_im);
02117 cpl_image_delete(perr_im);
02118 } else {
02119 cpl_image *pq_im = NULL;
02120 cpl_image *pu_im = NULL;
02121 cpl_image *pl_im = NULL;
02122
02123 cpl_image *pqnull_im = NULL;
02124 cpl_image *punull_im = NULL;
02125
02126 cpl_image *pqerr_im = NULL;
02127 cpl_image *puerr_im = NULL;
02128 cpl_image *plerr_im = NULL;
02129
02130 cpl_image *pang_im = NULL;
02131 cpl_image *pangerr_im = NULL;
02132
02133 double *p_q = NULL;
02134 double *p_u = NULL;
02135 double *p_l = NULL;
02136
02137 double *p_qnull = NULL;
02138 double *p_unull = NULL;
02139
02140 double *pqerr = NULL;
02141 double *puerr = NULL;
02142 double *plerr = NULL;
02143
02144 double *pang = NULL;
02145 double *pangerr = NULL;
02146
02147 int k, m;
02148
02149 cpl_image * correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
02150 double * correct = cpl_image_get_data_double(correct_im);
02151
02152 double mean_unull, mean_qnull;
02153
02154 int p = -1;
02155 int total = 0;
02156
02157 pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02158 pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02159 pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02160
02161 pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02162 puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02163 plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02164
02165 pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02166 pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02167
02168 p_q = cpl_image_get_data_double(pq_im);
02169 p_u = cpl_image_get_data_double(pu_im);
02170 p_l = cpl_image_get_data_double(pl_im);
02171
02172 if (nscience / 4 > 1) {
02173 pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02174 punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
02175
02176 p_qnull = cpl_image_get_data_double(pqnull_im);
02177 p_unull = cpl_image_get_data_double(punull_im);
02178 } else {
02179 cpl_msg_warning(cpl_func,
02180 "Not enough pairs to compute null parameters");
02181 }
02182
02183 pqerr = cpl_image_get_data_double(pqerr_im);
02184 puerr = cpl_image_get_data_double(puerr_im);
02185 plerr = cpl_image_get_data_double(plerr_im);
02186
02187 pang = cpl_image_get_data_double(pang_im);
02188 pangerr = cpl_image_get_data_double(pangerr_im);
02189
02190 if (chromatism) {
02191 cpl_table * chrotbl =
02192 dfs_load_table(frameset, chrom_table_tag, 1);
02193
02194 int nrow = cpl_table_get_nrow(chrotbl);
02195 float * lambda = cpl_table_get_data_float(chrotbl, "lambda");
02196 float * theta = cpl_table_get_data_float(chrotbl, "eps_theta");
02197
02198 for (j = 0; j < nx; j++) {
02199 double c_wave =
02200 startwavelength + dispersion / 2 + j * dispersion;
02201
02202 int found = 0;
02203
02204 for (k = 0; k < nrow - 1; k++) {
02205 if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
02206 found = 1;
02207 break;
02208 }
02209 }
02210
02211 if (found) {
02212 correct[j] = (theta [k + 1] - theta [k]) /
02213 (lambda[k + 1] - lambda[k]) *
02214 (c_wave - lambda[k]) + theta[k];
02215 correct[j] *= M_PI / 180;
02216 }
02217 else if (j)
02218 correct[j] = correct[j-1];
02219 else
02220 correct[j] = 0.0;
02221
02222 }
02223
02224 cpl_table_delete(chrotbl);
02225 }
02226
02227 for (j = 0; j < nobjects; j++) {
02228 double * ip_q, * ip_u, * ip_l,
02229 * ip_qnull, * ip_unull, * ipqerr, * ipuerr, * iplerr,
02230 * ipang, * ipangerr;
02231
02232 float * data;
02233 float * iffq, * ierrq, * iffu, * ierru;
02234
02235 int pos, pos_d;
02236
02237 ip_q = p_q + (nobjects - 1 - j) * nx;
02238 ip_u = p_u + (nobjects - 1 - j) * nx;
02239 ip_l = p_l + (nobjects - 1 - j) * nx;
02240
02241 if (nscience / 4 > 1) {
02242 ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
02243 ip_unull = p_unull + (nobjects - 1 - j) * nx;
02244 }
02245
02246 ipqerr = pqerr + (nobjects - 1 - j) * nx;
02247 ipuerr = puerr + (nobjects - 1 - j) * nx;
02248 iplerr = plerr + (nobjects - 1 - j) * nx;
02249
02250 ipang = pang + (nobjects - 1 - j) * nx;
02251 ipangerr = pangerr + (nobjects - 1 - j) * nx;
02252
02253 while (total < j + 1) {
02254 p++;
02255 total += nobjs_per_slit[p];
02256 }
02257
02258 for (k = 0; k < nscience / 4; k++) {
02259 float * if_o, * if_e, * ifdelta_o, * ifdelta_e;
02260
02261
02262
02263 pos = fors_find_angle_pos(angles, nscience, 90 * k);
02264 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
02265
02266 data = cpl_image_get_data_float(reduceds[pos]);
02267
02268 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
02269 + (total - j - 1)) * nx;
02270
02271 if_e = data + (2 * (nobjects - total)
02272 + (total - j - 1)) * nx;
02273
02274
02275
02276
02277 data = cpl_image_get_data_float(reduceds[pos_d]);
02278
02279 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
02280 + (total - j - 1)) * nx;
02281
02282 ifdelta_e = data + (2 * (nobjects - total)
02283 + (total - j - 1)) * nx;
02284
02285
02286
02287
02288 for (m = 0; m < nx; m++) {
02289
02290 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02291 (if_o[m] - if_e[m] ) /
02292 (if_o[m] + if_e[m] ) -
02293 (ifdelta_o[m] - ifdelta_e[m]) /
02294 (ifdelta_o[m] + ifdelta_e[m]);
02295
02296 quantity = isfinite(quantity) ? quantity : 0.0;
02297
02298
02299 ip_q[m] += quantity * 0.5 / (nscience / 4);
02300
02301
02302 if (nscience / 4 > 1) {
02303 if (k % 2)
02304 ip_qnull[m] += quantity * 0.5 / (nscience / 4);
02305 else
02306 ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
02307 }
02308 }
02309
02310
02311
02312 pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
02313 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
02314
02315 data = cpl_image_get_data_float(reduceds[pos]);
02316
02317 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
02318 + (total - j - 1)) * nx;
02319
02320 if_e = data + (2 * (nobjects - total)
02321 + (total - j - 1)) * nx;
02322
02323
02324
02325
02326 data = cpl_image_get_data_float(reduceds[pos_d]);
02327
02328 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
02329 + (total - j - 1)) * nx;
02330
02331 ifdelta_e = data + (2 * (nobjects - total)
02332 + (total - j - 1)) * nx;
02333
02334
02335
02336
02337 for (m = 0; m < nx; m++) {
02338
02339 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
02340 (if_o[m] - if_e[m] ) /
02341 (if_o[m] + if_e[m] ) -
02342 (ifdelta_o[m] - ifdelta_e[m]) /
02343 (ifdelta_o[m] + ifdelta_e[m]);
02344
02345 quantity = isfinite(quantity) ? quantity : 0.0;
02346
02347
02348 ip_u[m] += quantity * 0.5 / (nscience / 4);
02349
02350
02351 if (nscience / 4 > 1) {
02352 if (k % 2)
02353 ip_unull[m] += quantity * 0.5 / (nscience / 4);
02354 else
02355 ip_unull[m] -= quantity * 0.5 / (nscience / 4);
02356 }
02357 }
02358 }
02359
02360
02361
02362 pos = fors_find_angle_pos(angles, nscience, 0.0);
02363
02364 data = cpl_image_get_data_float(reduceds[pos]);
02365 iffq = data + 2 * (nobjects - 1 - j) * nx;
02366
02367 data = cpl_image_get_data_float(rerrors[pos]);
02368 ierrq = data + 2 * (nobjects - 1 - j) * nx;
02369
02370 pos = fors_find_angle_pos(angles, nscience, 22.5);
02371
02372 data = cpl_image_get_data_float(reduceds[pos]);
02373 iffu = data + 2 * (nobjects - 1 - j) * nx;
02374
02375 data = cpl_image_get_data_float(rerrors[pos]);
02376 ierru = data + 2 * (nobjects - 1 - j) * nx;
02377
02378 for (m = 0; m < nx; m++) {
02379
02380 double radicand;
02381
02382 ipqerr[m] = iffq[m] <= 0.0 ?
02383 0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
02384
02385 ipuerr[m] = iffu[m] <= 0.0 ?
02386 0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
02387
02388 iplerr[m] = CPL_MATH_SQRT1_2 * 0.5 * (ipqerr[m] + ipuerr[m]);
02389
02390
02391 if (chromatism) {
02392 ip_q[m] = ip_q[m] * cos(2 * correct[m]) -
02393 ip_u[m] * sin(2 * correct[m]);
02394
02395 ip_u[m] = ip_q[m] * sin(2 * correct[m]) +
02396 ip_u[m] * cos(2 * correct[m]);
02397 }
02398
02399
02400
02401 ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
02402
02403
02404 ipang[m] = (ip_q[m] == 0.0 ?
02405 (ip_u[m] > 0.0 ? 45.0 : 135.0)
02406 : 0.5 * (atan2(ip_u[m], ip_q[m]) * 180 / M_PI +
02407 ((atan2(ip_u[m], ip_q[m]) > 0.0 ? 0.0 : 360.0))));
02408
02409
02410 radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] +
02411 ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
02412
02413 ipangerr[m] = ip_l[m] == 0.0 ? 0.0 :
02414 sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI;
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433 }
02434
02435 if (nscience / 4 > 1) {
02436 float * weights;
02437 float max, sum, sum2, imean;
02438
02439 int k;
02440
02441
02442 weights = cpl_malloc(sizeof(float) * nx);
02443
02444 max = 0.0;
02445 for (k = 0; k < nx; k++) {
02446 if (max < iffq[k]) max = iffq[k];
02447 }
02448
02449 for (k = 0; k < nx; k++) {
02450 weights[k] = iffq[k] < 0.0 ?
02451 0.0 : iffq[k] * iffq[k] / (max * max);
02452 }
02453
02454 sum = 0.0;
02455 sum2 = 0.0;
02456 for (k = 0; k < nx; k++) {
02457 sum += weights[k] * ip_qnull[k];
02458 sum2 += weights[k];
02459 }
02460
02461 cpl_free(weights);
02462
02463 imean = sum / sum2;
02464
02465 mean_qnull += (imean - mean_qnull) / (j + 1.0);
02466
02467
02468 weights = cpl_malloc(sizeof(float) * nx);
02469
02470 max = 0.0;
02471 for (k = 0; k < nx; k++) {
02472 if (max < iffu[k]) max = iffu[k];
02473 }
02474
02475 for (k = 0; k < nx; k++) {
02476 weights[k] = iffu[k] < 0.0 ?
02477 0.0 : iffu[k] * iffu[k] / (max * max);
02478 }
02479
02480 sum = 0.0;
02481 sum2 = 0.0;
02482 for (k = 0; k < nx; k++) {
02483 sum += weights[k] * ip_unull[k];
02484 sum2 += weights[k];
02485 }
02486
02487 cpl_free(weights);
02488
02489 imean = sum / sum2;
02490
02491 mean_unull += (imean - mean_unull) / (j + 1.0);
02492 }
02493 }
02494
02495 cpl_image_delete(correct_im);
02496
02497 if (dfs_save_image(frameset, pq_im, reduced_q_tag, header,
02498 parlist, recipe, version))
02499 fors_pmos_extract_exit(NULL);
02500
02501 if (dfs_save_image(frameset, pu_im, reduced_u_tag, header,
02502 parlist, recipe, version))
02503 fors_pmos_extract_exit(NULL);
02504
02505 if (dfs_save_image(frameset, pl_im, reduced_l_tag, header,
02506 parlist, recipe, version))
02507 fors_pmos_extract_exit(NULL);
02508
02509 if (nscience / 4 > 1) {
02510 char *pipefile;
02511 char *keyname;
02512 cpl_propertylist *qheader = dfs_load_header(frameset,
02513 science_tag, 0);
02514
02515 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02516 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02517 cpl_propertylist_update_double(qheader, "CRVAL1",
02518 startwavelength + dispersion/2);
02519 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02520
02521
02522 cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02523 cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02524 cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02525 cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02526 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02527 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02528
02529 fors_qc_start_group(qheader, "2.0", instrume);
02530
02531
02532
02533
02534
02535 if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag,
02536 "Product category", instrume))
02537 fors_pmos_extract_exit("Cannot write product category to "
02538 "QC log file");
02539
02540 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02541 "DPR type", instrume))
02542 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02543 "lamp header");
02544
02545 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02546 "Template", instrume))
02547 fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02548 "lamp header");
02549
02550 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02551 "Grism name", instrume))
02552 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02553 "lamp header");
02554
02555 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02556 "Grism identifier", instrume))
02557 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02558 "lamp header");
02559
02560 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02561 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02562 "Filter name", instrume);
02563
02564 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02565 "Collimator name", instrume))
02566 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02567 "lamp header");
02568
02569 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02570 "Chip identifier", instrume))
02571 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02572 "lamp header");
02573
02574 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02575 "Archive name of input data",
02576 instrume))
02577 fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02578 "lamp header");
02579
02580 pipefile = dfs_generate_filename(reduced_nul_q_tag);
02581 if (fors_qc_write_string("PIPEFILE", pipefile,
02582 "Pipeline product name", instrume))
02583 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02584 cpl_free(pipefile); pipefile = NULL;
02585
02586
02587
02588
02589
02590
02591 keyname = "QC.NULL.Q.MEAN";
02592
02593 if (fors_qc_write_qc_double(qheader, mean_qnull,
02594 keyname, NULL,
02595 "Mean Q null parameter",
02596 instrume)) {
02597 fors_pmos_extract_exit("Cannot write mean Q null parameter "
02598 "to QC log file");
02599 }
02600
02601 fors_qc_end_group();
02602
02603 if (dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader,
02604 parlist, recipe, version))
02605 fors_pmos_extract_exit(NULL);
02606
02607 cpl_propertylist_delete(qheader);
02608
02609 qheader = dfs_load_header(frameset, science_tag, 0);
02610
02611 cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
02612 cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
02613 cpl_propertylist_update_double(qheader, "CRVAL1",
02614 startwavelength + dispersion/2);
02615 cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
02616
02617
02618 cpl_propertylist_update_double(qheader, "CD1_1", dispersion);
02619 cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
02620 cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
02621 cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
02622 cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
02623 cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
02624
02625 fors_qc_start_group(qheader, "2.0", instrume);
02626
02627
02628
02629
02630
02631 if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag,
02632 "Product category", instrume))
02633 fors_pmos_extract_exit("Cannot write product category to "
02634 "QC log file");
02635
02636 if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
02637 "DPR type", instrume))
02638 fors_pmos_extract_exit("Missing keyword DPR TYPE in arc "
02639 "lamp header");
02640
02641 if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
02642 "Template", instrume))
02643 fors_pmos_extract_exit("Missing keyword TPL ID in arc "
02644 "lamp header");
02645
02646 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
02647 "Grism name", instrume))
02648 fors_pmos_extract_exit("Missing keyword INS GRIS1 NAME in arc "
02649 "lamp header");
02650
02651 if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
02652 "Grism identifier", instrume))
02653 fors_pmos_extract_exit("Missing keyword INS GRIS1 ID in arc "
02654 "lamp header");
02655
02656 if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
02657 fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
02658 "Filter name", instrume);
02659
02660 if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
02661 "Collimator name", instrume))
02662 fors_pmos_extract_exit("Missing keyword INS COLL NAME in arc "
02663 "lamp header");
02664
02665 if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
02666 "Chip identifier", instrume))
02667 fors_pmos_extract_exit("Missing keyword DET CHIP1 ID in arc "
02668 "lamp header");
02669
02670 if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
02671 "Archive name of input data",
02672 instrume))
02673 fors_pmos_extract_exit("Missing keyword ARCFILE in arc "
02674 "lamp header");
02675
02676 pipefile = dfs_generate_filename(reduced_nul_u_tag);
02677 if (fors_qc_write_string("PIPEFILE", pipefile,
02678 "Pipeline product name", instrume))
02679 fors_pmos_extract_exit("Cannot write PIPEFILE to QC log file");
02680 cpl_free(pipefile); pipefile = NULL;
02681
02682
02683
02684
02685
02686
02687 keyname = "QC.NULL.U.MEAN";
02688
02689 if (fors_qc_write_qc_double(qheader, mean_unull,
02690 keyname, NULL,
02691 "Mean U null parameter",
02692 instrume)) {
02693 fors_pmos_extract_exit("Cannot write mean U null parameter "
02694 "to QC log file");
02695 }
02696
02697 fors_qc_end_group();
02698
02699 if (dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader,
02700 parlist, recipe, version))
02701 fors_pmos_extract_exit(NULL);
02702
02703 cpl_propertylist_delete(qheader);
02704 }
02705
02706 if (dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header,
02707 parlist, recipe, version))
02708 fors_pmos_extract_exit(NULL);
02709
02710 if (dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header,
02711 parlist, recipe, version))
02712 fors_pmos_extract_exit(NULL);
02713
02714 if (dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header,
02715 parlist, recipe, version))
02716 fors_pmos_extract_exit(NULL);
02717
02718 if (dfs_save_image(frameset, pang_im, reduced_angle_tag, header,
02719 parlist, recipe, version))
02720 fors_pmos_extract_exit(NULL);
02721
02722 if (dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag,
02723 header, parlist, recipe, version))
02724 fors_pmos_extract_exit(NULL);
02725
02726 cpl_image_delete(pq_im);
02727 cpl_image_delete(pu_im);
02728 cpl_image_delete(pl_im);
02729
02730 cpl_image_delete(pqnull_im);
02731 cpl_image_delete(punull_im);
02732
02733 cpl_image_delete(pqerr_im);
02734 cpl_image_delete(puerr_im);
02735 cpl_image_delete(plerr_im);
02736 cpl_image_delete(pang_im);
02737 cpl_image_delete(pangerr_im);
02738 }
02739
02740 cpl_propertylist_delete(header);
02741
02742
02743
02744 for (j = 0; j < nscience; j++) {
02745 cpl_image_delete(reduceds[j]);
02746 cpl_image_delete(rerrors[j]);
02747 cpl_table_delete(slitss[j]);
02748 cpl_image_delete(mappeds[j]);
02749 }
02750
02751 cpl_free(reduceds);
02752 cpl_free(rerrors);
02753 cpl_free(slitss);
02754 cpl_free(mappeds);
02755
02756 cpl_free(instrume); instrume = NULL;
02757
02758 cpl_free(skylocalmaps);
02759 cpl_free(nobjs_per_slit);
02760
02761 if (cpl_error_get_code()) {
02762 cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
02763 fors_pmos_extract_exit(NULL);
02764 }
02765 else
02766 return 0;
02767 }
02768
02769
02780
02781 static float * fors_check_angles(cpl_frameset * frameset,
02782 int pmos, const char *tag, int * circ)
02783 {
02784 float *angles = NULL;
02785 cpl_frame *c_frame = NULL;
02786 char *ret_id = NULL;
02787
02788 int i = 0;
02789
02790 angles = cpl_malloc(sizeof(float) * pmos);
02791
02792 for (c_frame = cpl_frameset_find(frameset, tag);
02793 c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
02794
02795 cpl_propertylist * header =
02796 cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
02797
02798 if (!ret_id) {
02799 ret_id = cpl_strdup(cpl_propertylist_get_string(header,
02800 "ESO INS OPTI4 ID"));
02801
02802 if (ret_id[1] != '5' && ret_id[1] != '4') {
02803 cpl_msg_error(cpl_func,
02804 "Unknown retarder plate id: %s", ret_id);
02805 return NULL;
02806 }
02807 } else {
02808 char * c_ret_id = (char *)
02809 cpl_propertylist_get_string(header, "ESO INS OPTI4 ID");
02810 if (ret_id[1] != c_ret_id[1]) {
02811 cpl_msg_error(cpl_func, "Input frames are not from the same "
02812 "retarder plate");
02813 return NULL;
02814 }
02815 }
02816
02817 if (ret_id[1] == '5') {
02818 angles[i] = (float)
02819 cpl_propertylist_get_double(header, "ESO INS RETA2 ROT");
02820 *circ = 0;
02821 } else {
02822 angles[i] = (float)
02823 cpl_propertylist_get_double(header, "ESO INS RETA4 ROT");
02824 *circ = 1;
02825 }
02826
02827 cpl_propertylist_delete(header);
02828 i++;
02829 }
02830
02831 cpl_free(ret_id);
02832
02833 if (*circ) {
02834 if (pmos != 2 && pmos != 4) {
02835 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02836 "found, but either 2 or 4 are required for "
02837 "circular polarization measurements!", pmos);
02838 return NULL;
02839 }
02840 } else {
02841 if (pmos != 4 && pmos != 8 && pmos != 16) {
02842 cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
02843 "found, but either 4, 8, or 16 are required for "
02844 "linear polarization measurements!", pmos);
02845 return NULL;
02846 }
02847 }
02848
02849
02850
02851 if (*circ) {
02852 for (i = 0; i < pmos; i++) {
02853 if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
02854 const char *cangles;
02855 switch (pmos) {
02856 case 2: cangles = "-45.0, 45.0"; break;
02857 case 4: cangles = "-45.0, 45.0, 135.0, 225.0"; break;
02858 default: assert(0);
02859 }
02860
02861 cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02862 "angle %.2f. All angles %s must be provided.",
02863 angles[i], cangles);
02864 return NULL;
02865 }
02866 }
02867 }
02868 else {
02869 for (i = 0; i < pmos; i++) {
02870 if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
02871 const char *cangles;
02872 switch (pmos) {
02873 case 4: cangles = "0.0, 22.5, 45.0, 67.5"; break;
02874 case 8: cangles = "0.0, 22.5, 45.0, 67.5, "
02875 "90.0, 112.5, 135.0, 157.5"; break;
02876 case 16: cangles = "0.0, 22.5, 45.0, 67.5, "
02877 "90.0, 112.5, 135.0, 157.5, "
02878 "180.0, 202.5, 225.0, 247.5, "
02879 "270.0, 292.5, 315.0, 337.5"; break;
02880 default: assert(0);
02881 }
02882
02883 cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
02884 "angle %.2f. All angles %s must be provided.",
02885 angles[i], cangles);
02886 return NULL;
02887 }
02888 }
02889 }
02890
02891 return angles;
02892 }
02893
02894
02902
02903 static int
02904 fors_find_angle_pos(float * angles, int nangles, float angle)
02905 {
02906 int i, match = 0;
02907
02908 for (i = 0; i < nangles; i++) {
02909 if (fabs(angles[i] - angle) < 1.0 ||
02910 fabs(angles[i] - 360.0 - angle) < 1.0) {
02911 match = 1;
02912 break;
02913 }
02914 }
02915
02916 return match ? i : -1;
02917 }