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 (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
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, 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
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
00744
00745
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
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;
00835
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
00982
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)
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;
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
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
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
01120
01121
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
01151
01152
01153 cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s",
01154 alltime);
01155
01156 cpl_msg_indent_less();
01157
01158
01159
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
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
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
01234
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
01245
01246
01247
01248
01249
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
01312
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
01344
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
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
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
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
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
01487
01488 if (cosmics) {
01489 cpl_msg_info(recipe, "Removing cosmic rays...");
01490 mos_clean_cosmics(spectra, gain, -1., -1.);
01491 }
01492
01493
01494
01495
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
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
01553 if (skymedian) {
01554 cpl_msg_indent_less();
01555 cpl_msg_info(recipe, "Local sky determination...");
01556 cpl_msg_indent_more();
01557
01558
01559
01560 skylocalmap = mos_sky_local_old(mapped, slits);
01561 cpl_image_subtract(mapped, skylocalmap);
01562
01563
01564
01565
01566
01567 cpl_image_delete(skylocalmap); skylocalmap = NULL;
01568 }
01569
01570
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
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
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
01690
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
01731
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
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
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
01818
01819
01820
01821
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
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
01859
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
01929
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
01940
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
01953 ip_v[m] += quantity * 0.5 / (nscience / 2);
01954
01955
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
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
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
02024
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
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
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;
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
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
02277
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
02288
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
02301 ip_q[m] += quantity * 0.5 / (nscience / 4);
02302
02303
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
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
02326
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
02337
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
02350 ip_u[m] += quantity * 0.5 / (nscience / 4);
02351
02352
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
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
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
02401
02402
02403 ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
02404
02405
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
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
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435 }
02436
02437 if (nscience / 4 > 1) {
02438 float * weights;
02439 float max, sum, sum2, imean;
02440
02441 int k;
02442
02443
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
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
02523
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
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
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
02619
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
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
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
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') {
02820 angles[i] = (float)
02821 cpl_propertylist_get_double(header, "ESO INS RETA2 ROT");
02822 *circ = 0;
02823 } else {
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
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 }