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