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