FORS Pipeline Reference Manual  5.3.10
fors_pmos_science.c
1 /* $Id: fors_pmos_science.c,v 1.65 2013-10-09 15:59:38 cgarcia Exp $
2  *
3  * This file is part of the FORS Data Reduction Pipeline
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013-10-09 15:59:38 $
24  * $Revision: 1.65 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <math.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <assert.h>
36 
37 #include <cpl.h>
38 #include <moses.h>
39 #include <fors_dfs.h>
40 #include <fors_utils.h>
41 #include <fors_qc.h>
42 
43 static int fors_pmos_science_create(cpl_plugin *);
44 static int fors_pmos_science_exec(cpl_plugin *);
45 static int fors_pmos_science_destroy(cpl_plugin *);
46 static int fors_pmos_science(cpl_parameterlist *, cpl_frameset *);
47 
48 static float * fors_check_angles(cpl_frameset *, int, const char *, int *);
49 static int
50 fors_find_angle_pos(float * angles, int nangles, float angle);
51 
52 static char fors_pmos_science_description[] =
53 "This recipe is used to reduce scientific spectra using the extraction\n"
54 "mask and the products created by the recipe fors_mpol_calib. The spectra\n"
55 "are bias subtracted, flat fielded (if a normalised flat field is specified)\n"
56 "and remapped eliminating the optical distortions. The wavelength calibration\n"
57 "can be optionally upgraded using a number of sky lines: if no sky lines\n"
58 "catalog of wavelengths is specified, an internal one is used instead.\n"
59 "If the alignment to the sky lines is performed, the input dispersion\n"
60 "coefficients table is upgraded and saved to disk, and a new CCD wavelengths\n"
61 "map is created.\n"
62 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n"
63 "depending on the instrument mode, and in particular on the grism used)\n"
64 "may also be specified: this table contains a default recipe parameter\n"
65 "setting to control the way spectra are extracted for a specific instrument\n"
66 "mode, as it is used for automatic run of the pipeline on Paranal and in\n"
67 "Garching. If this table is specified, it will modify the default recipe\n"
68 "parameter setting, with the exception of those parameters which have been\n"
69 "explicitly modifyed on the command line. If a grism table is not specified,\n"
70 "the input recipe parameters values will always be read from the command\n"
71 "line, or from an esorex configuration file if present, or from their\n"
72 "generic default values (that are rarely meaningful).\n"
73 "Either a scientific or a standard star exposure can be specified in input.\n"
74 "The acronym SCI on products should be read STD in case of standard stars\n"
75 "observations.\n\n"
76 "Input files:\n\n"
77 " DO category: Type: Explanation: Required:\n"
78 " SCIENCE_PMOS Raw Scientific exposure Y\n"
79 " or STANDARD_PMOS Raw Standard star exposure Y\n"
80 " MASTER_BIAS Calib Master bias Y\n"
81 " GRISM_TABLE Calib Grism table .\n"
82 " MASTER_SKYLINECAT Calib Sky lines catalog .\n"
83 " MASTER_NORM_FLAT_PMOS Calib Normalised flat field .\n"
84 " DISP_COEFF_PMOS Calib Inverse dispersion Y\n"
85 " CURV_COEFF_PMOS Calib Spectral curvature Y\n"
86 " SLIT_LOCATION_PMOS Calib Slits positions table Y\n"
87 " RETARDER_WAVEPLATE_CHROMATISM Calib Chromatism correction .\n"
88 " STD_PMOS_TABLE Calib Linear pol. of std stars .\n"
89 "\n"
90 "Output files:\n\n"
91 " DO category: Data type: Explanation:\n"
92 " REDUCED_SCI_PMOS FITS image Extracted scientific spectra\n"
93 " REDUCED_SKY_SCI_PMOS FITS image Extracted sky spectra\n"
94 " REDUCED_ERROR_SCI_PMOS FITS image Errors on extracted spectra\n"
95 " REDUCED_X_SCI_PMOS FITS image X Stokes parameter (and L)\n"
96 " REDUCED_ERROR_X_SCI_PMOS FITS image Error on X Stokes parameter\n"
97 " REDUCED_NUL_X_SCI_PMOS FITS image Null parameter for X\n"
98 " REDUCED_ANGLE_SCI_PMOS FITS image Direction of linear polarization\n"
99 " REDUCED_ERROR_ANGLE_SCI_PMOS FITS image Error on polarization direction\n"
100 " UNMAPPED_SCI_PMOS FITS image Sky subtracted scientific spectra\n"
101 " MAPPED_SCI_PMOS FITS image Rectified scientific spectra\n"
102 " MAPPED_ALL_SCI_PMOS FITS image Rectified science spectra with sky\n"
103 " MAPPED_SKY_SCI_PMOS FITS image Rectified sky spectra\n"
104 " UNMAPPED_SKY_SCI_PMOS FITS image Sky on CCD\n"
105 " OBJECT_TABLE_SCI_PMOS FITS table Positions of detected objects\n"
106 " OBJECT_TABLE_POL_SCI_PMOS FITS table Positions of real objects\n"
107 "\n"
108 " Only if the sky-alignment of the wavelength solution is requested:\n"
109 " DISP_COEFF_SCI_PMOS FITS table Upgraded dispersion coefficients\n"
110 " WAVELENGTH_MAP_SCI_PMOS FITS image Upgraded wavelength map\n\n";
111 
112 #define fors_pmos_science_exit(message, nscience) \
113 { \
114 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
115 if(reduceds != NULL) { \
116  for (j = 0; j < nscience; j++) \
117  cpl_image_delete(reduceds[j]); \
118 } \
119 if(rerrors != NULL) { \
120  for (j = 0; j < nscience; j++) \
121  cpl_image_delete(rerrors[j]); \
122 } \
123 if(slitss != NULL) { \
124  for (j = 0; j < nscience; j++) \
125  cpl_table_delete(slitss[j]); \
126 } \
127 if(mappeds != NULL) { \
128  for (j = 0; j < nscience; j++) \
129  cpl_image_delete(mappeds[j]); \
130 } \
131 if(skylocalmaps != NULL) { \
132  for (j = 0; j < nscience; j++) \
133  cpl_image_delete(skylocalmaps[j]); \
134 } \
135 cpl_free(reduceds); \
136 cpl_free(rerrors); \
137 cpl_free(slitss); \
138 cpl_free(mappeds); \
139 cpl_free(skylocalmaps); \
140 cpl_free(instrume); \
141 cpl_image_delete(dummy); \
142 cpl_image_delete(mapped_sky); \
143 cpl_image_delete(mapped_cleaned); \
144 cpl_image_delete(skymap); \
145 cpl_image_delete(smapped); \
146 cpl_table_delete(offsets); \
147 cpl_table_delete(sky); \
148 cpl_image_delete(bias); \
149 cpl_image_delete(spectra); \
150 cpl_image_delete(coordinate); \
151 cpl_image_delete(norm_flat); \
152 cpl_image_delete(rainbow); \
153 cpl_image_delete(rectified); \
154 cpl_image_delete(wavemap); \
155 cpl_propertylist_delete(header); \
156 cpl_propertylist_delete(save_header); \
157 cpl_table_delete(grism_table); \
158 cpl_table_delete(idscoeff); \
159 cpl_table_delete(maskslits); \
160 cpl_table_delete(overscans); \
161 cpl_table_delete(polytraces); \
162 cpl_table_delete(wavelengths); \
163 cpl_table_delete(mask_science); \
164 cpl_table_delete(mask_arc); \
165 cpl_table_delete(mask_flat); \
166 cpl_vector_delete(lines); \
167 cpl_msg_indent_less(); \
168 return -1; \
169 }
170 
171 
172 #define fors_pmos_science_exit_memcheck(message) \
173 { \
174 if ((const char *)message != NULL) cpl_msg_info(recipe, message); \
175 cpl_free(instrume); \
176 cpl_image_delete(dummy); \
177 cpl_image_delete(mapped_cleaned); \
178 cpl_image_delete(mapped_sky); \
179 cpl_image_delete(skymap); \
180 cpl_image_delete(smapped); \
181 cpl_table_delete(offsets); \
182 cpl_table_delete(sky); \
183 cpl_image_delete(bias); \
184 cpl_image_delete(spectra); \
185 cpl_image_delete(coordinate); \
186 cpl_image_delete(norm_flat); \
187 cpl_image_delete(rainbow); \
188 cpl_image_delete(rectified); \
189 cpl_image_delete(wavemap); \
190 cpl_propertylist_delete(header); \
191 cpl_propertylist_delete(save_header); \
192 cpl_table_delete(grism_table); \
193 cpl_table_delete(idscoeff); \
194 cpl_table_delete(maskslits); \
195 cpl_table_delete(overscans); \
196 cpl_table_delete(polytraces); \
197 cpl_table_delete(wavelengths); \
198 cpl_table_delete(mask_science); \
199 cpl_table_delete(mask_arc); \
200 cpl_table_delete(mask_flat); \
201 cpl_vector_delete(lines); \
202 cpl_msg_indent_less(); \
203 return 0; \
204 }
205 
206 
218 int cpl_plugin_get_info(cpl_pluginlist *plist)
219 {
220  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
221  cpl_plugin *plugin = &recipe->interface;
222 
223  cpl_plugin_init(plugin,
224  CPL_PLUGIN_API,
225  FORS_BINARY_VERSION,
226  CPL_PLUGIN_TYPE_RECIPE,
227  "fors_pmos_science",
228  "Extraction of scientific spectra",
229  fors_pmos_science_description,
230  "Carlo Izzo",
231  PACKAGE_BUGREPORT,
232  "This file is currently part of the FORS Instrument Pipeline\n"
233  "Copyright (C) 2002-2010 European Southern Observatory\n\n"
234  "This program is free software; you can redistribute it and/or modify\n"
235  "it under the terms of the GNU General Public License as published by\n"
236  "the Free Software Foundation; either version 2 of the License, or\n"
237  "(at your option) any later version.\n\n"
238  "This program is distributed in the hope that it will be useful,\n"
239  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
240  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
241  "GNU General Public License for more details.\n\n"
242  "You should have received a copy of the GNU General Public License\n"
243  "along with this program; if not, write to the Free Software Foundation,\n"
244  "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
245  fors_pmos_science_create,
246  fors_pmos_science_exec,
247  fors_pmos_science_destroy);
248 
249  cpl_pluginlist_append(plist, plugin);
250 
251  return 0;
252 }
253 
254 
265 static int fors_pmos_science_create(cpl_plugin *plugin)
266 {
267  cpl_recipe *recipe;
268  cpl_parameter *p;
269 
270 
271  /*
272  * Check that the plugin is part of a valid recipe
273  */
274 
275  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
276  recipe = (cpl_recipe *)plugin;
277  else
278  return -1;
279 
280  /*
281  * Create the parameters list in the cpl_recipe object
282  */
283 
284  recipe->parameters = cpl_parameterlist_new();
285 
286 
287  /*
288  * Dispersion
289  */
290 
291  p = cpl_parameter_new_value("fors.fors_pmos_science.dispersion",
292  CPL_TYPE_DOUBLE,
293  "Expected spectral dispersion (Angstrom/pixel)",
294  "fors.fors_pmos_science",
295  0.0);
296  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
297  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
298  cpl_parameterlist_append(recipe->parameters, p);
299 
300  /*
301  * Rebin
302  */
303 
304  p = cpl_parameter_new_value("fors.fors_pmos_science.rebin",
305  CPL_TYPE_INT,
306  "Rebin (pixel)",
307  "fors.fors_pmos_science",
308  1);
309  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rebin");
310  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
311  cpl_parameterlist_append(recipe->parameters, p);
312 
313  /*
314  * Sky lines alignment
315  */
316 
317  p = cpl_parameter_new_value("fors.fors_pmos_science.skyalign",
318  CPL_TYPE_INT,
319  "Polynomial order for sky lines alignment, "
320  "or -1 to avoid alignment",
321  "fors.fors_pmos_science",
322  0);
323  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
324  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
325  cpl_parameterlist_append(recipe->parameters, p);
326 
327  /*
328  * Line catalog table column containing the sky reference wavelengths
329  */
330 
331  p = cpl_parameter_new_value("fors.fors_pmos_science.wcolumn",
332  CPL_TYPE_STRING,
333  "Name of sky line catalog table column "
334  "with wavelengths",
335  "fors.fors_pmos_science",
336  "WLEN");
337  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
338  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
339  cpl_parameterlist_append(recipe->parameters, p);
340 
341  /*
342  * Start wavelength for spectral extraction
343  */
344 
345  p = cpl_parameter_new_value("fors.fors_pmos_science.startwavelength",
346  CPL_TYPE_DOUBLE,
347  "Start wavelength in spectral extraction",
348  "fors.fors_pmos_science",
349  0.0);
350  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
351  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
352  cpl_parameterlist_append(recipe->parameters, p);
353 
354  /*
355  * End wavelength for spectral extraction
356  */
357 
358  p = cpl_parameter_new_value("fors.fors_pmos_science.endwavelength",
359  CPL_TYPE_DOUBLE,
360  "End wavelength in spectral extraction",
361  "fors.fors_pmos_science",
362  0.0);
363  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
364  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
365  cpl_parameterlist_append(recipe->parameters, p);
366 
367  /*
368  * Flux conservation
369  */
370 
371  p = cpl_parameter_new_value("fors.fors_pmos_science.flux",
372  CPL_TYPE_BOOL,
373  "Apply flux conservation",
374  "fors.fors_pmos_science",
375  TRUE);
376  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
377  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
378  cpl_parameterlist_append(recipe->parameters, p);
379 
380  /*
381  * Apply flat field
382  */
383 
384  p = cpl_parameter_new_value("fors.fors_pmos_science.flatfield",
385  CPL_TYPE_BOOL,
386  "Apply flat field",
387  "fors.fors_pmos_science",
388  TRUE);
389  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flatfield");
390  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
391  cpl_parameterlist_append(recipe->parameters, p);
392 
393  /*
394  * Median sky subtraction method
395  */
396 
397  p = cpl_parameter_new_value("fors.fors_pmos_science.skymedian",
398  CPL_TYPE_BOOL,
399  "Sky subtraction from extracted slit spectra",
400  "fors.fors_pmos_science",
401  FALSE);
402  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skymedian");
403  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
404  cpl_parameterlist_append(recipe->parameters, p);
405 
406  /*
407  * Local sky subtraction on CCD spectra
408  */
409 
410  p = cpl_parameter_new_value("fors.fors_pmos_science.skylocal",
411  CPL_TYPE_BOOL,
412  "Sky subtraction from CCD slit spectra",
413  "fors.fors_pmos_science",
414  TRUE);
415  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skylocal");
416  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
417  cpl_parameterlist_append(recipe->parameters, p);
418 
419  /*
420  * Cosmic rays removal
421  */
422 
423  p = cpl_parameter_new_value("fors.fors_pmos_science.cosmics",
424  CPL_TYPE_BOOL,
425  "Eliminate cosmic rays hits (only if local "
426  "sky subtraction is also requested)",
427  "fors.fors_pmos_science",
428  FALSE);
429  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cosmics");
430  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
431  cpl_parameterlist_append(recipe->parameters, p);
432 
433  /*
434  * Slit margin
435  */
436 
437  p = cpl_parameter_new_value("fors.fors_pmos_science.slit_margin",
438  CPL_TYPE_INT,
439  "Number of pixels to exclude at each slit "
440  "in object detection and extraction",
441  "fors.fors_pmos_science",
442  3);
443  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "slit_margin");
444  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
445  cpl_parameterlist_append(recipe->parameters, p);
446 
447  /*
448  * Extraction radius
449  */
450 
451  p = cpl_parameter_new_value("fors.fors_pmos_science.ext_radius",
452  CPL_TYPE_INT,
453  "Maximum extraction radius for detected "
454  "objects (pixel)",
455  "fors.fors_pmos_science",
456  12);
457  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_radius");
458  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
459  cpl_parameterlist_append(recipe->parameters, p);
460 
461  /*
462  * Contamination radius
463  */
464 
465  p = cpl_parameter_new_value("fors.fors_pmos_science.cont_radius",
466  CPL_TYPE_INT,
467  "Minimum distance at which two objects "
468  "of equal luminosity do not contaminate "
469  "each other (pixel)",
470  "fors.fors_pmos_science",
471  0);
472  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cont_radius");
473  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
474  cpl_parameterlist_append(recipe->parameters, p);
475 
476  /*
477  * Object extraction method
478  */
479 
480  p = cpl_parameter_new_value("fors.fors_pmos_science.ext_mode",
481  CPL_TYPE_INT,
482  "Object extraction method: 0 = aperture, "
483  "1 = Horne optimal extraction",
484  "fors.fors_pmos_science",
485  1);
486  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ext_mode");
487  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
488  cpl_parameterlist_append(recipe->parameters, p);
489 
490  /*
491  * Tolerance in object matching
492  */
493 
494  p = cpl_parameter_new_value("fors.fors_pmos_science.match_tolerance",
495  CPL_TYPE_DOUBLE,
496  "Tolerance for matching spectra from the "
497  "same object at different angles and beams "
498  "(pixel)",
499  "fors.fors_pmos_science",
500  5.0);
501  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "match_tolerance");
502  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
503  cpl_parameterlist_append(recipe->parameters, p);
504 
505  /*
506  * Normalise output by exposure time
507  */
508 
509  p = cpl_parameter_new_value("fors.fors_pmos_science.time_normalise",
510  CPL_TYPE_BOOL,
511  "Normalise output spectra by the exposure time",
512  "fors.fors_pmos_science",
513  TRUE);
514  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "time_normalise");
515  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
516  cpl_parameterlist_append(recipe->parameters, p);
517 
518  /*
519  * Apply chromatism correction to polarization angle
520  */
521 
522  p = cpl_parameter_new_value("fors.fors_pmos_science.chromatism",
523  CPL_TYPE_BOOL,
524  "Chromatism correction to polarization angles",
525  "fors.fors_pmos_science",
526  TRUE);
527  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "chromatism");
528  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
529  cpl_parameterlist_append(recipe->parameters, p);
530 
531  /*
532  * Rotation correction for linear polarisation
533  */
534 
535  p = cpl_parameter_new_value("fors.fors_pmos_science.wollaston",
536  CPL_TYPE_BOOL,
537  "Wollaston mounting (FORS2 only): true = 0 degrees "
538  "(ord. beam on top, extr. beam on bottom), "
539  "false = 180 degrees (beams are reversed), for FORS1 "
540  "is frozen to true",
541  "fors.fors_pmos_science",
542  TRUE);
543  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wollaston");
544  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
545  cpl_parameterlist_append(recipe->parameters, p);
546 
547  /*
548  * Computation of QC1 parameters
549  */
550 
551  p = cpl_parameter_new_value("fors.fors_pmos_science.qc",
552  CPL_TYPE_BOOL,
553  "Compute QC1 parameters",
554  "fors.fors_pmos_science",
555  TRUE);
556  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "qc");
557  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
558  cpl_parameterlist_append(recipe->parameters, p);
559 
560  return 0;
561 }
562 
563 
572 static int fors_pmos_science_exec(cpl_plugin *plugin)
573 {
574  cpl_recipe *recipe;
575 
576  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
577  recipe = (cpl_recipe *)plugin;
578  else
579  return -1;
580 
581  return fors_pmos_science(recipe->parameters, recipe->frames);
582 }
583 
584 
593 static int fors_pmos_science_destroy(cpl_plugin *plugin)
594 {
595  cpl_recipe *recipe;
596 
597  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
598  recipe = (cpl_recipe *)plugin;
599  else
600  return -1;
601 
602  cpl_parameterlist_delete(recipe->parameters);
603 
604  return 0;
605 }
606 
607 
617 static int fors_pmos_science(cpl_parameterlist *parlist, cpl_frameset *frameset)
618 {
619 
620  const char *recipe = "fors_pmos_science";
621 
622 
623  /*
624  * Input parameters
625  */
626 
627  double dispersion;
628  int group;
629  int skyalign;
630  const char *wcolumn;
631  double startwavelength;
632  double endwavelength;
633  int flux;
634  int flatfield;
635  int skylocal;
636  int skymedian;
637  int chromatism;
638  double wollaston;
639  int cosmics;
640  int slit_margin;
641  int ext_radius;
642  int cont_radius;
643  int ext_mode;
644  double tolerance;
645  int time_normalise;
646  int qc;
647 
648  /*
649  * CPL objects
650  */
651 
652  cpl_image **images;
653 
654  cpl_image **reduceds = NULL;
655  cpl_image **rerrors = NULL;
656  cpl_table **slitss = NULL;
657  cpl_image **mappeds = NULL;
658  cpl_image **skylocalmaps = NULL;
659 
660  int nobjects = 0;
661 
662  cpl_image *bias = NULL;
663  cpl_image *norm_flat = NULL;
664  cpl_image *spectra = NULL;
665  cpl_image *rectified = NULL;
666  cpl_image *coordinate = NULL;
667  cpl_image *rainbow = NULL;
668  cpl_image *mapped = NULL;
669  cpl_image *mapped_sky = NULL;
670  cpl_image *mapped_cleaned = NULL;
671  cpl_image *smapped = NULL;
672  cpl_image *wavemap = NULL;
673  cpl_image *skymap = NULL;
674  cpl_image *skylocalmap = NULL;
675  cpl_image *dummy = NULL;
676 
677  cpl_table *grism_table = NULL;
678  cpl_table *overscans = NULL;
679  cpl_table *wavelengths = NULL;
680  cpl_table *idscoeff = NULL;
681  cpl_table *slits = NULL;
682  cpl_table *origslits = NULL;
683  cpl_table *maskslits = NULL;
684  cpl_table *mask_science = NULL;
685  cpl_table *mask_arc = NULL;
686  cpl_table *mask_flat = NULL;
687  cpl_table *polytraces = NULL;
688  cpl_table *offsets = NULL;
689  cpl_table *sky = NULL;
690 
691  cpl_vector *lines = NULL;
692 
693  cpl_propertylist *header = NULL;
694  cpl_propertylist *save_header = NULL;
695 
696  /*
697  * Auxiliary variables
698  */
699 
700  char version[80];
701  char *instrume = NULL;
702  const char *science_tag;
703  const char *master_norm_flat_tag;
704  const char *disp_coeff_tag;
705  const char *disp_coeff_sky_tag;
706  const char *wavelength_map_sky_tag;
707  const char *curv_coeff_tag;
708  const char *slit_location_tag;
709  const char *reduced_science_tag;
710  const char *reduced_sky_tag;
711  const char *reduced_error_tag;
712  const char *mapped_science_tag;
713  const char *unmapped_science_tag;
714  const char *mapped_science_sky_tag;
715  const char *mapped_sky_tag;
716  const char *unmapped_sky_tag;
717  const char *object_table_tag;
718  const char *object_table_pol_tag;
719  const char *skylines_offsets_tag;
720  const char *reduced_q_tag;
721  const char *reduced_u_tag;
722  const char *reduced_v_tag;
723  const char *reduced_l_tag;
724  const char *reduced_i_tag;
725  const char *reduced_error_q_tag;
726  const char *reduced_error_u_tag;
727  const char *reduced_error_v_tag;
728  const char *reduced_error_l_tag;
729  const char *reduced_error_i_tag;
730  const char *reduced_nul_q_tag;
731  const char *reduced_nul_u_tag;
732  const char *reduced_nul_v_tag;
733  const char *reduced_angle_tag;
734  const char *reduced_error_angle_tag;
735  const char *chrom_table_tag = "RETARDER_WAVEPLATE_CHROMATISM";
736  const char *std_pmos_table_tag = "STD_PMOS_TABLE";
737  const cpl_frame *ref_sci_frame = NULL;
738  float *angles = NULL;
739  int pmos, circ;
740  int nscience = 0;
741  double alltime;
742  double mean_rms;
743  int nlines;
744  int rebin;
745  double *line;
746  int nx = 0, ny;
747  double reference;
748  double gain;
749  double ron;
750  double ra, dec;
751  char filter;
752  double qc_angle;
753  double qc_angle_err;
754  double qc_pl;
755  double qc_pl_err;
756  int standard;
757  int polarised;
758  int highres;
759  int i, j;
760 
761  int *nobjs_per_slit;
762  int nslits;
763 
764  int bagoo = 0;
765  double blevel = 0.0;
766  int doit = 0; // montecarlo simulation
767  int conta = 0; // Bagoo, conta gli oggetti con S/N > s2n
768  int bright = 0; // Bagoo, marca un oggetto con S/N > s2n
769  int nslits_out_det = 0;
770 
771 
772  cpl_error_code error;
773 
774  snprintf(version, 80, "%s-%s", PACKAGE, PACKAGE_VERSION);
775 
776  if (bagoo) {
777  char *montecarlo = getenv("MONTECARLO");
778 
779  if (montecarlo) {
780  doit = atoi(montecarlo);
781  }
782  }
783 
784  cpl_msg_set_indentation(2);
785 
786  fors_dfs_set_groups(frameset);
787 
788 
789  /*
790  * Get configuration parameters
791  */
792 
793  cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
794  cpl_msg_indent_more();
795 
796  if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
797  fors_pmos_science_exit("Too many in input: GRISM_TABLE", nscience);
798 
799  grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
800 
801  dispersion = dfs_get_parameter_double(parlist,
802  "fors.fors_pmos_science.dispersion", grism_table);
803 
804  if (dispersion <= 0.0)
805  fors_pmos_science_exit("Invalid spectral dispersion", nscience);
806 
807  group = dfs_get_parameter_int(parlist,
808  "fors.fors_pmos_science.rebin", NULL);
809 
810  if (group < 1)
811  fors_pmos_science_exit("Invalid rebin factor", nscience);
812 
813  skyalign = dfs_get_parameter_int(parlist,
814  "fors.fors_pmos_science.skyalign", NULL);
815 
816  if (skyalign > 2)
817  fors_pmos_science_exit("Max polynomial degree for sky alignment is 2", nscience);
818 
819  wcolumn = dfs_get_parameter_string(parlist,
820  "fors.fors_pmos_science.wcolumn", NULL);
821 
822  startwavelength = dfs_get_parameter_double(parlist,
823  "fors.fors_pmos_science.startwavelength", grism_table);
824  if (startwavelength < 3000.0 || startwavelength > 13000.0)
825  fors_pmos_science_exit("Invalid wavelength", nscience);
826 
827  endwavelength = dfs_get_parameter_double(parlist,
828  "fors.fors_pmos_science.endwavelength", grism_table);
829  if (endwavelength < 3000.0 || endwavelength > 13000.0)
830  fors_pmos_science_exit("Invalid wavelength", nscience);
831 
832  if (endwavelength - startwavelength <= 0.0)
833  fors_pmos_science_exit("Invalid wavelength interval", nscience);
834 
835  flux = dfs_get_parameter_bool(parlist, "fors.fors_pmos_science.flux", NULL);
836 
837  flatfield = dfs_get_parameter_bool(parlist,
838  "fors.fors_pmos_science.flatfield",
839  NULL);
840 
841  skylocal = dfs_get_parameter_bool(parlist,
842  "fors.fors_pmos_science.skylocal",
843  NULL);
844  skymedian = dfs_get_parameter_bool(parlist,
845  "fors.fors_pmos_science.skymedian",
846  NULL);
847 
848  chromatism = dfs_get_parameter_bool(parlist,
849  "fors.fors_pmos_science.chromatism",
850  NULL);
851 
852  wollaston = dfs_get_parameter_bool(parlist,
853  "fors.fors_pmos_science.wollaston",
854  NULL);
855 
856  wollaston = wollaston ? 0 : 1;
857 
858  if (skylocal && skymedian)
859  fors_pmos_science_exit("Cannot apply sky subtraction both on "
860  "extracted and non-extracted spectra", nscience);
861 
862  cosmics = dfs_get_parameter_bool(parlist,
863  "fors.fors_pmos_science.cosmics", NULL);
864 
865  if (cosmics)
866  if (!skylocal)
867  fors_pmos_science_exit("Cosmic rays correction requires "
868  "skylocal=true", nscience);
869 
870  slit_margin = dfs_get_parameter_int(parlist,
871  "fors.fors_pmos_science.slit_margin",
872  NULL);
873  if (slit_margin < 0)
874  fors_pmos_science_exit("Value must be zero or positive", nscience);
875 
876  ext_radius = dfs_get_parameter_int(parlist,
877  "fors.fors_pmos_science.ext_radius",
878  NULL);
879  if (ext_radius < 0)
880  fors_pmos_science_exit("Value must be zero or positive", nscience);
881 
882  cont_radius = dfs_get_parameter_int(parlist,
883  "fors.fors_pmos_science.cont_radius",
884  NULL);
885  if (cont_radius < 0)
886  fors_pmos_science_exit("Value must be zero or positive", nscience);
887 
888  ext_mode = dfs_get_parameter_int(parlist, "fors.fors_pmos_science.ext_mode",
889  NULL);
890  if (ext_mode < 0 || ext_mode > 1)
891  fors_pmos_science_exit("Invalid object extraction mode", nscience);
892 
893  tolerance = dfs_get_parameter_double(parlist,
894  "fors.fors_pmos_science.match_tolerance", NULL);
895  if (tolerance <= 0.0)
896  fors_pmos_science_exit("Invalid object match tolerance", nscience);
897 
898  time_normalise = dfs_get_parameter_bool(parlist,
899  "fors.fors_pmos_science.time_normalise", NULL);
900 
901  qc = dfs_get_parameter_bool(parlist, "fors.fors_pmos_science.qc", NULL);
902 
903  cpl_table_delete(grism_table); grism_table = NULL;
904 
905  if (cpl_error_get_code())
906  fors_pmos_science_exit("Failure getting the configuration parameters",nscience);
907 
908 
909  /*
910  * Check input set-of-frames
911  */
912 
913  cpl_msg_indent_less();
914  cpl_msg_info(recipe, "Check input set-of-frames:");
915  cpl_msg_indent_more();
916 
917  {
918  cpl_frameset *subframeset = cpl_frameset_duplicate(frameset);
919  cpl_frameset_erase(subframeset, "MASTER_BIAS");
920 
921  if (!dfs_equal_keyword(subframeset, "ESO INS GRIS1 ID"))
922  cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
923 
924  if (!dfs_equal_keyword(subframeset, "ESO INS FILT1 ID"))
925  cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
926 
927  if (!dfs_equal_keyword(subframeset, "ESO DET CHIP1 ID"))
928  cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
929 
930  cpl_frameset_delete(subframeset);
931  }
932 
933  standard = 0;
934  pmos = cpl_frameset_count_tags(frameset, "SCIENCE_PMOS");
935 
936  if (pmos == 0) {
937  pmos = cpl_frameset_count_tags(frameset, "STANDARD_PMOS");
938  standard = 1;
939  }
940 
941  if (pmos == 0)
942  fors_pmos_science_exit("Missing input scientific frame", nscience);
943 
944  angles = fors_check_angles(frameset, pmos,
945  standard ? "STANDARD_PMOS" : "SCIENCE_PMOS",
946  &circ);
947  if (angles == NULL)
948  fors_pmos_science_exit("Polarization angles could not be read", nscience);
949 
950  if (circ)
951  chromatism = 0; /* Chromatism correction unrequired for
952  circular polarimetry */
953 
954 
955  nscience = pmos;
956 
957  reduceds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
958  rerrors = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
959  slitss = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
960  mappeds = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
961  skylocalmaps = (cpl_image **)cpl_malloc(sizeof(cpl_image *) * nscience);
962 
963  if (pmos) {
964  cpl_msg_info(recipe, "PMOS data found");
965  if (standard) {
966  science_tag = "STANDARD_PMOS";
967  reduced_science_tag = "REDUCED_STD_PMOS";
968  unmapped_science_tag = "UNMAPPED_STD_PMOS";
969  mapped_science_tag = "MAPPED_STD_PMOS";
970  mapped_science_sky_tag = "MAPPED_ALL_STD_PMOS";
971  skylines_offsets_tag = "SKY_SHIFTS_SLIT_STD_PMOS";
972  wavelength_map_sky_tag = "WAVELENGTH_MAP_STD_PMOS";
973  disp_coeff_sky_tag = "DISP_COEFF_STD_PMOS";
974  mapped_sky_tag = "MAPPED_SKY_STD_PMOS";
975  unmapped_sky_tag = "UNMAPPED_SKY_STD_PMOS";
976  object_table_tag = "OBJECT_TABLE_STD_PMOS";
977  object_table_pol_tag = "OBJECT_TABLE_POL_STD_PMOS";
978  reduced_sky_tag = "REDUCED_SKY_STD_PMOS";
979  reduced_error_tag = "REDUCED_ERROR_STD_PMOS";
980  reduced_q_tag = "REDUCED_Q_STD_PMOS";
981  reduced_u_tag = "REDUCED_U_STD_PMOS";
982  reduced_v_tag = "REDUCED_V_STD_PMOS";
983  reduced_l_tag = "REDUCED_L_STD_PMOS";
984  reduced_i_tag = "REDUCED_I_STD_PMOS";
985  reduced_error_q_tag = "REDUCED_ERROR_Q_STD_PMOS";
986  reduced_error_u_tag = "REDUCED_ERROR_U_STD_PMOS";
987  reduced_error_v_tag = "REDUCED_ERROR_V_STD_PMOS";
988  reduced_error_l_tag = "REDUCED_ERROR_L_STD_PMOS";
989  reduced_error_i_tag = "REDUCED_ERROR_I_STD_PMOS";
990  reduced_nul_q_tag = "REDUCED_NUL_Q_STD_PMOS";
991  reduced_nul_u_tag = "REDUCED_NUL_U_STD_PMOS";
992  reduced_nul_v_tag = "REDUCED_NUL_V_STD_PMOS";
993  reduced_angle_tag = "REDUCED_ANGLE_STD_PMOS";
994  reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_STD_PMOS";
995  }
996  else {
997  science_tag = "SCIENCE_PMOS";
998  reduced_science_tag = "REDUCED_SCI_PMOS";
999  unmapped_science_tag = "UNMAPPED_SCI_PMOS";
1000  mapped_science_tag = "MAPPED_SCI_PMOS";
1001  mapped_science_sky_tag = "MAPPED_ALL_SCI_PMOS";
1002  skylines_offsets_tag = "SKY_SHIFTS_SLIT_SCI_PMOS";
1003  wavelength_map_sky_tag = "WAVELENGTH_MAP_SCI_PMOS";
1004  disp_coeff_sky_tag = "DISP_COEFF_SCI_PMOS";
1005  mapped_sky_tag = "MAPPED_SKY_SCI_PMOS";
1006  unmapped_sky_tag = "UNMAPPED_SKY_SCI_PMOS";
1007  object_table_tag = "OBJECT_TABLE_SCI_PMOS";
1008  object_table_pol_tag = "OBJECT_TABLE_POL_SCI_PMOS";
1009  reduced_sky_tag = "REDUCED_SKY_SCI_PMOS";
1010  reduced_error_tag = "REDUCED_ERROR_SCI_PMOS";
1011  reduced_q_tag = "REDUCED_Q_SCI_PMOS";
1012  reduced_u_tag = "REDUCED_U_SCI_PMOS";
1013  reduced_v_tag = "REDUCED_V_SCI_PMOS";
1014  reduced_l_tag = "REDUCED_L_SCI_PMOS";
1015  reduced_i_tag = "REDUCED_I_SCI_PMOS";
1016  reduced_error_q_tag = "REDUCED_ERROR_Q_SCI_PMOS";
1017  reduced_error_u_tag = "REDUCED_ERROR_U_SCI_PMOS";
1018  reduced_error_v_tag = "REDUCED_ERROR_V_SCI_PMOS";
1019  reduced_error_l_tag = "REDUCED_ERROR_L_SCI_PMOS";
1020  reduced_error_i_tag = "REDUCED_ERROR_I_SCI_PMOS";
1021  reduced_nul_q_tag = "REDUCED_NUL_Q_SCI_PMOS";
1022  reduced_nul_u_tag = "REDUCED_NUL_U_SCI_PMOS";
1023  reduced_nul_v_tag = "REDUCED_NUL_V_SCI_PMOS";
1024  reduced_angle_tag = "REDUCED_ANGLE_SCI_PMOS";
1025  reduced_error_angle_tag = "REDUCED_ERROR_ANGLE_SCI_PMOS";
1026  }
1027 
1028  master_norm_flat_tag = "MASTER_NORM_FLAT_PMOS";
1029  disp_coeff_tag = "DISP_COEFF_PMOS";
1030  curv_coeff_tag = "CURV_COEFF_PMOS";
1031  slit_location_tag = "SLIT_LOCATION_PMOS";
1032 
1033  if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
1034  master_norm_flat_tag = "MASTER_NORM_FLAT_LONG_PMOS";
1035  disp_coeff_tag = "DISP_COEFF_LONG_PMOS";
1036  slit_location_tag = "SLIT_LOCATION_LONG_PMOS";
1037  }
1038  }
1039 
1040  if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") == 0)
1041  fors_pmos_science_exit("Missing required input: MASTER_BIAS", nscience);
1042 
1043  if (cpl_frameset_count_tags(frameset, "MASTER_BIAS") > 1)
1044  fors_pmos_science_exit("Too many in input: MASTER_BIAS", nscience);
1045 
1046  if (skyalign >= 0)
1047  if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
1048  fors_pmos_science_exit("Too many in input: MASTER_SKYLINECAT", nscience);
1049 
1050  if (cpl_frameset_count_tags(frameset, disp_coeff_tag) == 0) {
1051  cpl_msg_error(recipe, "Missing required input: %s", disp_coeff_tag);
1052  fors_pmos_science_exit(NULL, nscience);
1053  }
1054 
1055  if (cpl_frameset_count_tags(frameset, disp_coeff_tag) > 1) {
1056  cpl_msg_error(recipe, "Too many in input: %s", disp_coeff_tag);
1057  fors_pmos_science_exit(NULL, nscience);
1058  }
1059 
1060  if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
1061  cpl_msg_error(recipe, "Missing required input: %s",
1062  slit_location_tag);
1063  fors_pmos_science_exit(NULL, nscience);
1064  }
1065 
1066  if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
1067  cpl_msg_error(recipe, "Too many in input: %s", slit_location_tag);
1068  fors_pmos_science_exit(NULL, nscience);
1069  }
1070 
1071  if (chromatism) {
1072  if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) {
1073  cpl_msg_error(recipe, "Missing required input: %s",
1074  chrom_table_tag);
1075  fors_pmos_science_exit(NULL, nscience);
1076  }
1077 
1078  if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) {
1079  cpl_msg_error(recipe, "Too many in input: %s", chrom_table_tag);
1080  fors_pmos_science_exit(NULL, nscience);
1081  }
1082  }
1083 
1084  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
1085  if (flatfield) {
1086  cpl_msg_error(recipe, "Too many in input: %s",
1087  master_norm_flat_tag);
1088  fors_pmos_science_exit(NULL, nscience);
1089  }
1090  else {
1091  cpl_msg_warning(recipe, "%s in input are ignored, "
1092  "since flat field correction was not requested",
1093  master_norm_flat_tag);
1094  }
1095  }
1096 
1097  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
1098  if (!flatfield) {
1099  cpl_msg_warning(recipe, "%s in input is ignored, "
1100  "since flat field correction was not requested",
1101  master_norm_flat_tag);
1102  }
1103  }
1104 
1105  if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
1106  if (flatfield) {
1107  cpl_msg_error(recipe, "Flat field correction was requested, "
1108  "but no %s are found in input",
1109  master_norm_flat_tag);
1110  fors_pmos_science_exit(NULL, nscience);
1111  }
1112  }
1113 
1114  if (standard) {
1115  if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) > 1) {
1116  cpl_msg_error(recipe, "Too many in input: %s", std_pmos_table_tag);
1117  fors_pmos_science_exit(NULL, nscience);
1118  }
1119 
1120  if (qc) {
1121  if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) == 0) {
1122  cpl_msg_error(recipe, "QC computation was requested, but no "
1123  "%s is found in input", std_pmos_table_tag);
1124  fors_pmos_science_exit(NULL, nscience);
1125  }
1126  }
1127  }
1128 
1129  cpl_msg_indent_less();
1130 
1131  ref_sci_frame = cpl_frameset_find_const(frameset, science_tag);
1132 
1133 
1134  /*
1135  * Get the reference wavelength and the rebin factor along the
1136  * dispersion direction from a scientific exposure
1137  */
1138 
1139  header = dfs_load_header(frameset, science_tag, 0);
1140 
1141  if (header == NULL)
1142  fors_pmos_science_exit("Cannot load scientific frame header", nscience);
1143 
1144  instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
1145  if (instrume == NULL)
1146  fors_pmos_science_exit("Missing keyword INSTRUME in scientific header", nscience);
1147  instrume = cpl_strdup(instrume);
1148 
1149  if (instrume[4] == '1')
1150  snprintf(version, 80, "%s/%s", "fors1", VERSION);
1151  if (instrume[4] == '2')
1152  snprintf(version, 80, "%s/%s", "fors2", VERSION);
1153 
1154  reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
1155 
1156  if (cpl_error_get_code() != CPL_ERROR_NONE)
1157  fors_pmos_science_exit("Missing keyword ESO INS GRIS1 WLEN in scientific "
1158  "frame header", nscience);
1159 
1160  if (reference < 3000.0) /* Perhaps in nanometers... */
1161  reference *= 10;
1162 
1163  if (reference < 3000.0 || reference > 13000.0) {
1164  cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
1165  "keyword ESO INS GRIS1 WLEN in scientific frame header",
1166  reference);
1167  fors_pmos_science_exit(NULL, nscience);
1168  }
1169 
1170  cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
1171 
1172  rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
1173 
1174  if (cpl_error_get_code() != CPL_ERROR_NONE)
1175  fors_pmos_science_exit("Missing keyword ESO DET WIN1 BINX in "
1176  "scientific frame header", nscience);
1177 
1178  if (rebin != 1) {
1179  dispersion *= rebin;
1180  cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
1181  "spectral dispersion used is %f A/pixel", rebin,
1182  dispersion);
1183  ext_radius /= rebin;
1184  cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
1185  "extraction radius used is %d pixel", rebin,
1186  ext_radius);
1187  }
1188 
1189  gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
1190 
1191  if (cpl_error_get_code() != CPL_ERROR_NONE)
1192  fors_pmos_science_exit("Missing keyword ESO DET OUT1 CONAD in "
1193  "scientific frame header", nscience);
1194 
1195  cpl_msg_info(recipe, "The gain factor is: %.2f e-/ADU", gain);
1196 
1197  ron = cpl_propertylist_get_double(header, "ESO DET OUT1 RON");
1198 
1199  if (cpl_error_get_code() != CPL_ERROR_NONE)
1200  fors_pmos_science_exit("Missing keyword ESO DET OUT1 RON in "
1201  "scientific frame header", nscience);
1202 
1203  ron /= gain; /* Convert from electrons to ADU */
1204 
1205  cpl_msg_info(recipe, "The read-out-noise is: %.2f ADU", ron);
1206 
1207  if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
1208  cpl_msg_error(recipe, "Missing required input: %s", curv_coeff_tag);
1209  fors_pmos_science_exit(NULL, nscience);
1210  }
1211 
1212  if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
1213  cpl_msg_error(recipe, "Too many in input: %s", curv_coeff_tag);
1214  fors_pmos_science_exit(NULL, nscience);
1215  }
1216 
1217  cpl_msg_info(recipe, "Load normalised flat field (if present)...");
1218  cpl_msg_indent_more();
1219 
1220  if (flatfield) {
1221  norm_flat = dfs_load_image(frameset, master_norm_flat_tag,
1222  CPL_TYPE_FLOAT, 0, 1);
1223  }
1224 
1225  if (skyalign >= 0) {
1226 
1227  cpl_msg_indent_less();
1228  cpl_msg_info(recipe, "Load input sky line catalog...");
1229  cpl_msg_indent_more();
1230 
1231  wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
1232 
1233  if (wavelengths) {
1234  /*
1235  * Cast the wavelengths into a (double precision) CPL vector
1236  */
1237 
1238  nlines = cpl_table_get_nrow(wavelengths);
1239 
1240  if (nlines == 0)
1241  fors_pmos_science_exit("Empty input sky line catalog", nscience);
1242 
1243  if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
1244  cpl_msg_error(recipe, "Missing column %s in input line "
1245  "catalog table", wcolumn);
1246  fors_pmos_science_exit(NULL, nscience);
1247  }
1248 
1249  line = cpl_malloc(nlines * sizeof(double));
1250 
1251  for (i = 0; i < nlines; i++)
1252  line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
1253 
1254  cpl_table_delete(wavelengths); wavelengths = NULL;
1255 
1256  lines = cpl_vector_wrap(nlines, line);
1257  }
1258  else {
1259  cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
1260  }
1261  }
1262 
1263  /*
1264  * Keep a table of slit positions according to science, in order to
1265  * check its consistency with those from arc and flat.
1266  */
1267 
1268  mask_science = mos_load_slits_fors_mos(header, &nslits_out_det);
1269 
1270  cpl_propertylist_delete(header); header = NULL;
1271 
1272  cpl_table_name_column(mask_science, "xtop", "science");
1273 
1274  /*
1275  * Load the wavelength calibration table
1276  */
1277 
1278  idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
1279 
1280  if (idscoeff == NULL)
1281  fors_pmos_science_exit("Cannot load wavelength calibration table", nscience);
1282 
1283  /*
1284  * Keep a table of slit positions according to arc, in order to
1285  * check its consistency with those from science and flat.
1286  */
1287 
1288  header = dfs_load_header(frameset, disp_coeff_tag, 0);
1289 
1290  mask_arc = mos_load_slits_fors_mos(header, &nslits_out_det);
1291 
1292  cpl_propertylist_delete(header); header = NULL;
1293 
1294  if (cpl_table_move_column(mask_science, "xtop", mask_arc)) {
1295  cpl_error_reset();
1296  cpl_msg_warning(recipe,
1297  "Slit configuration of science and arc differs!");
1298  cpl_table_delete(mask_arc); mask_arc = NULL;
1299  goto skip;
1300  }
1301  cpl_table_name_column(mask_science, "xtop", "arc");
1302  cpl_table_delete(mask_arc); mask_arc = NULL;
1303 
1304  if (norm_flat) {
1305 
1306  /*
1307  * Keep a table of slit positions according to arc, in order to
1308  * check its consistency with those from science and flat.
1309  */
1310 
1311  header = dfs_load_header(frameset, master_norm_flat_tag, 0);
1312 
1313  mask_flat = mos_load_slits_fors_mos(header, &nslits_out_det);
1314 
1315  cpl_propertylist_delete(header); header = NULL;
1316 
1317  if (cpl_table_move_column(mask_science, "xtop", mask_flat)) {
1318  cpl_error_reset();
1319  cpl_msg_warning(recipe,
1320  "Slit configuration of science and flat differs!");
1321  cpl_table_delete(mask_flat); mask_flat = NULL;
1322  goto skip;
1323  }
1324  cpl_table_name_column(mask_science, "xtop", "flat");
1325  cpl_table_delete(mask_flat); mask_flat = NULL;
1326  }
1327 
1328  cpl_table_duplicate_column(mask_science, "diff", mask_science, "science");
1329  cpl_table_subtract_columns(mask_science, "diff", "arc");
1330  cpl_table_abs_column(mask_science, "diff");
1331 
1332  if (cpl_table_get_column_max(mask_science, "diff") > 0.01) {
1333  cpl_msg_warning(recipe,
1334  "Slit configuration of science and arc differs!");
1335  goto skip;
1336  }
1337 
1338  if (norm_flat) {
1339  cpl_table_erase_column(mask_science, "diff");
1340 
1341  cpl_table_duplicate_column(mask_science, "diff",
1342  mask_science, "science");
1343  cpl_table_subtract_columns(mask_science, "diff", "flat");
1344  cpl_table_abs_column(mask_science, "diff");
1345 
1346  if (cpl_table_get_column_max(mask_science, "diff") > 0.01) {
1347  cpl_msg_warning(recipe,
1348  "Slit configuration of science and flat differs!");
1349  goto skip;
1350  }
1351  }
1352 
1353 skip:
1354 
1355  cpl_table_delete(mask_science); mask_science = NULL;
1356 
1357  for (j = 0; j < nscience; j++) {
1358  int k;
1359 
1360  cpl_msg_indent_less();
1361  cpl_msg_info(recipe, "Processing scientific exposure of angle %.2f "
1362  "(%d out of %d) ...",
1363  angles[j], j + 1, nscience);
1364  cpl_msg_indent_more();
1365 
1366  cpl_msg_info(recipe, "Load scientific exposure...");
1367  cpl_msg_indent_more();
1368 
1369 
1370  /*
1371  * FIXME: Horrible workaround to avoid the problem because of the
1372  * multiple encapsulation of cpl_frameset_find() in different
1373  * loading functions
1374  */
1375 
1376  header = dfs_load_header(frameset, science_tag, 0);
1377 
1378  for (k = 0; k < j; k ++) {
1379  cpl_propertylist_delete(header);
1380  header = dfs_load_header(frameset, NULL, 0);
1381  }
1382 
1383  spectra = dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
1384 
1385  for (k = 0; k < j; k ++) {
1386  cpl_image_delete(spectra);
1387  spectra = dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0, 0);
1388  }
1389 
1390  if (spectra == NULL)
1391  fors_pmos_science_exit("Cannot load scientific frame", nscience);
1392 
1393  if (header == NULL)
1394  fors_pmos_science_exit("Cannot load scientific frame header", nscience);
1395 
1396  alltime = cpl_propertylist_get_double(header, "EXPTIME");
1397 
1398  if (cpl_error_get_code() != CPL_ERROR_NONE)
1399  fors_pmos_science_exit("Missing keyword EXPTIME in scientific "
1400  "frame header", nscience);
1401 
1402  cpl_msg_info(recipe, "Scientific frame exposure time: %.2f s",
1403  alltime);
1404 
1405  ra = cpl_propertylist_get_double(header, "RA");
1406  dec = cpl_propertylist_get_double(header, "DEC");
1407 
1408  if (cpl_error_get_code() != CPL_ERROR_NONE)
1409  fors_pmos_science_exit("Missing keywords RA and DEC in scientific "
1410  "frame header", nscience);
1411 
1412  /* Leave the header on for the next step... */
1413 
1414  cpl_msg_indent_less();
1415 
1416  /*
1417  * Remove the master bias
1418  */
1419 
1420  cpl_msg_info(recipe, "Remove the master bias...");
1421 
1422  bias = dfs_load_image(frameset, "MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
1423 
1424  if (bias == NULL)
1425  fors_pmos_science_exit("Cannot load master bias", nscience);
1426 
1427  if (doit) {
1428  if (j == 0)
1429  blevel = cpl_image_get_mean(bias);
1430  mos_randomise_image(spectra, ron, gain, blevel);
1431  }
1432 
1433  overscans = mos_load_overscans_fors(header);
1434 
1435  dummy = mos_remove_bias(spectra, bias, overscans);
1436  cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
1437  cpl_image_delete(bias); bias = NULL;
1438  cpl_table_delete(overscans); overscans = NULL;
1439 
1440  if (spectra == NULL)
1441  fors_pmos_science_exit("Cannot remove bias from scientific frame", nscience);
1442 
1443  nx = cpl_image_get_size_x(spectra);
1444  ny = cpl_image_get_size_y(spectra);
1445 
1446  if (flatfield) {
1447 
1448  if (norm_flat) {
1449  cpl_msg_info(recipe, "Apply flat field correction...");
1450  if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
1451  cpl_msg_error(recipe,
1452  "Failure of flat field correction: %s",
1453  cpl_error_get_message());
1454  fors_pmos_science_exit(NULL, nscience);
1455  }
1456  }
1457  else {
1458  cpl_msg_error(recipe, "Cannot load input %s for flat field "
1459  "correction", master_norm_flat_tag);
1460  fors_pmos_science_exit(NULL, nscience);
1461  }
1462 
1463  }
1464 
1465  /*
1466  * Load the spectral curvature table
1467  */
1468 
1469  polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
1470  if (polytraces == NULL)
1471  fors_pmos_science_exit("Cannot load spectral curvature table", nscience);
1472 
1473  /*
1474  * Load the slit location table
1475  */
1476 
1477  slits = dfs_load_table(frameset, slit_location_tag, 1);
1478  if (slits == NULL)
1479  fors_pmos_science_exit("Cannot load slits location table", nscience);
1480 
1481  cpl_msg_info(recipe, "Processing scientific spectra...");
1482 
1483  /*
1484  * This one will also generate the spatial map from the spectral
1485  * curvature table (in the case of multislit data)
1486  */
1487 
1488  coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1489 
1490  smapped = mos_spatial_calibration(spectra, slits, polytraces,
1491  reference, startwavelength,
1492  endwavelength, dispersion,
1493  flux, coordinate);
1494 
1495  /*
1496  * Generate a rectified wavelength map from the wavelength calibration
1497  * table
1498  */
1499 
1500  rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
1501  endwavelength);
1502 
1503  if (dispersion > 1.0)
1504  highres = 0;
1505  else
1506  highres = 1;
1507 
1508  if (skyalign >= 0) {
1509  if (skyalign) {
1510  cpl_msg_info(recipe,
1511  "Align wavelength solution to reference skylines "
1512  "applying %d order residual fit...", skyalign);
1513  }
1514  else {
1515  cpl_msg_info(recipe, "Align wavelength solution to reference "
1516  "skylines applying median offset...");
1517  }
1518 
1519  if (!j) {
1520  offsets = mos_wavelength_align(smapped, slits, reference,
1521  startwavelength, endwavelength,
1522  idscoeff, lines, highres,
1523  skyalign, rainbow, 4);
1524  if (offsets) {
1525  if (standard)
1526  cpl_msg_warning(recipe, "Alignment of the wavelength "
1527  "solution to reference sky lines may "
1528  "be unreliable in this case!");
1529 
1530  fors_dfs_save_table(frameset, offsets,
1531  skylines_offsets_tag, NULL,
1532  parlist, recipe, ref_sci_frame);
1533  if(cpl_error_get_code() != CPL_ERROR_NONE)
1534  fors_pmos_science_exit(NULL, nscience);
1535 
1536  } else {
1537  cpl_msg_warning(recipe, "Alignment of the wavelength "
1538  "solution to reference sky lines could "
1539  "not be done!");
1540  skyalign = -1;
1541  }
1542  }
1543 
1544 
1545  }
1546 
1547  wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
1548  polytraces, reference,
1549  startwavelength, endwavelength,
1550  dispersion);
1551 
1552 
1553  cpl_image_delete(rainbow); rainbow = NULL;
1554  cpl_image_delete(coordinate); coordinate = NULL;
1555 
1556  /*
1557  * Here the wavelength calibrated slit spectra are created. This frame
1558  * contains sky_science.
1559  */
1560 
1561  mapped_sky = mos_wavelength_calibration(smapped, reference,
1562  startwavelength, endwavelength,
1563  dispersion, idscoeff, flux);
1564 
1565  if (!j) {
1566  cpl_msg_indent_less();
1567  cpl_msg_info(recipe,
1568  "Check applied wavelength against skylines...");
1569  cpl_msg_indent_more();
1570 
1571  mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength,
1572  dispersion, 6, highres);
1573 
1574 
1575  cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
1576 
1577  mean_rms = cpl_table_get_column_mean(idscoeff, "error");
1578 
1579  cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
1580  mean_rms, mean_rms * dispersion);
1581  }
1582 
1583  save_header = cpl_propertylist_duplicate(header);
1584 
1585  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1586  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1587  cpl_propertylist_update_double(header, "CRVAL1",
1588  startwavelength + dispersion/2);
1589  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1590  cpl_propertylist_update_double(header, "CD1_1", dispersion);
1591  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1592  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1593  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1594  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1595  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1596 
1597  if (time_normalise) {
1598  dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
1599 
1600  if (!j) {
1601  if(dfs_save_image_null(frameset, parlist,
1602  mapped_science_sky_tag,
1603  recipe, version)) {
1604  fors_pmos_science_exit(NULL, nscience);
1605  }
1606  }
1607 
1608  if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) {
1609  fors_pmos_science_exit(NULL, nscience);
1610  }
1611 
1612  cpl_image_delete(dummy); dummy = NULL;
1613  }
1614  else {
1615 
1616  if (!j) {
1617  if(dfs_save_image_null(frameset, parlist,
1618  mapped_science_sky_tag,
1619  recipe, version)) {
1620  fors_pmos_science_exit(NULL, nscience);
1621  }
1622  }
1623 
1624  if (dfs_save_image_ext(mapped_sky,
1625  mapped_science_sky_tag, header)) {
1626  fors_pmos_science_exit(NULL, nscience);
1627  }
1628 
1629  }
1630 
1631  if (skymedian == 0 && skylocal == 0) {
1632  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1633  }
1634 
1635  if (skylocal) {
1636 
1637  cpl_msg_indent_less();
1638 
1639  cpl_msg_info(recipe, "Local sky determination...");
1640  cpl_msg_indent_more();
1641  skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
1642  startwavelength, endwavelength, dispersion);
1643 
1644  if (skymap) {
1645  if (time_normalise)
1646  cpl_image_divide_scalar(skymap, alltime);
1647 
1648  if (!j) {
1649  if(dfs_save_image_null(frameset, parlist,
1650  unmapped_sky_tag,
1651  recipe, version)) {
1652  fors_pmos_science_exit(NULL, nscience);
1653  }
1654  }
1655 
1656  if (dfs_save_image_ext(skymap, unmapped_sky_tag,
1657  save_header)) {
1658  fors_pmos_science_exit(NULL, nscience);
1659  }
1660 
1661  cpl_image_delete(skymap); skymap = NULL;
1662 
1663  if (!j) {
1664  if(dfs_save_image_null(frameset, parlist,
1665  unmapped_science_tag,
1666  recipe, version)) {
1667  fors_pmos_science_exit(NULL, nscience);
1668  }
1669  }
1670 
1671  if (dfs_save_image_ext(spectra, unmapped_science_tag,
1672  save_header)) {
1673  fors_pmos_science_exit(NULL, nscience);
1674  }
1675 
1676  if (cosmics) {
1677  cpl_msg_info(recipe, "Removing cosmic rays...");
1678  mos_clean_cosmics(spectra, gain, -1., -1.);
1679  }
1680 
1681  /*
1682  * The spatially rectified image, that contained the sky,
1683  * is replaced by a sky-subtracted spatially rectified image:
1684  */
1685 
1686  cpl_image_delete(smapped); smapped = NULL;
1687 
1688  smapped = mos_spatial_calibration(spectra, slits, polytraces,
1689  reference, startwavelength,
1690  endwavelength, dispersion,
1691  flux, NULL);
1692  }
1693  else {
1694  cpl_msg_warning(recipe, "Sky subtraction failure");
1695  if (cosmics)
1696  cpl_msg_warning(recipe,
1697  "Cosmic rays removal not performed!");
1698  cosmics = skylocal = 0;
1699  }
1700  }
1701 
1702  cpl_image_delete(spectra); spectra = NULL;
1703  cpl_table_delete(polytraces); polytraces = NULL;
1704 
1705  if (skyalign >= 0) {
1706  save_header = dfs_load_header(frameset, science_tag, 0);
1707 
1708  if (!j) {
1709  if(dfs_save_image_null(frameset, parlist,
1710  wavelength_map_sky_tag,
1711  recipe, version)) {
1712  fors_pmos_science_exit(NULL, nscience);
1713  }
1714  }
1715 
1716  if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag,
1717  save_header)) {
1718  fors_pmos_science_exit(NULL, nscience);
1719  }
1720  }
1721 
1722  cpl_image_delete(wavemap); wavemap = NULL;
1723 
1724  mapped = mos_wavelength_calibration(smapped, reference,
1725  startwavelength, endwavelength,
1726  dispersion, idscoeff, flux);
1727 
1728  cpl_image_delete(smapped); smapped = NULL;
1729 
1730  if (skyalign >= 0) {
1731  if (!j) {
1732  fors_dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag,
1733  NULL, parlist, recipe, ref_sci_frame);
1734  if(cpl_error_get_code() != CPL_ERROR_NONE)
1735  fors_pmos_science_exit(NULL, nscience);
1736  }
1737  }
1738 
1739  if (skymedian) {
1740  cpl_msg_indent_less();
1741  cpl_msg_info(recipe, "Local sky determination...");
1742  cpl_msg_indent_more();
1743 
1744  skylocalmap = mos_sky_local_old(mapped, slits);
1745  cpl_image_subtract(mapped, skylocalmap);
1746  cpl_image_delete(skylocalmap); skylocalmap = NULL;
1747  }
1748 
1749  if (skymedian || skylocal) {
1750 
1751  skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
1752 
1753  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1754 
1755  if (time_normalise) {
1756  dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
1757 
1758  if (!j) {
1759  if(dfs_save_image_null(frameset, parlist,
1760  mapped_sky_tag,
1761  recipe, version)) {
1762  fors_pmos_science_exit(NULL, nscience);
1763  }
1764  }
1765 
1766  if (dfs_save_image_ext(dummy, mapped_sky_tag,
1767  header)) {
1768  fors_pmos_science_exit(NULL, nscience);
1769  }
1770 
1771  cpl_image_delete(dummy); dummy = NULL;
1772  }
1773  else {
1774  if (!j) {
1775  if(dfs_save_image_null(frameset, parlist,
1776  mapped_sky_tag,
1777  recipe, version)) {
1778  fors_pmos_science_exit(NULL, nscience);
1779  }
1780  }
1781 
1782  if (dfs_save_image_ext(skylocalmap, mapped_sky_tag,
1783  header)) {
1784  fors_pmos_science_exit(NULL, nscience);
1785  }
1786  }
1787 
1788  skylocalmaps[j] = skylocalmap;
1789 
1790  cpl_msg_indent_less();
1791  cpl_msg_info(recipe, "Object detection...");
1792  cpl_msg_indent_more();
1793 
1794  if (!j) {
1795  origslits = cpl_table_duplicate(slits);
1796  nslits = cpl_table_get_nrow(slits);
1797  }
1798 
1799  if (cosmics || nscience > 1) {
1800  dummy = mos_detect_objects(mapped, slits, slit_margin,
1801  ext_radius, cont_radius);
1802  }
1803  else {
1804  mapped_cleaned = cpl_image_duplicate(mapped);
1805  mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
1806  dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin,
1807  ext_radius, cont_radius);
1808 
1809  cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
1810  }
1811 
1812  cpl_image_delete(dummy); dummy = NULL;
1813 
1814  }
1815 
1816  slitss[j] = slits;
1817  mappeds[j] = mapped;
1818 
1819  cpl_msg_indent_less();
1820 
1821  cpl_propertylist_delete(header); header = NULL;
1822  cpl_propertylist_delete(save_header); save_header = NULL;
1823  }
1824 
1825  cpl_table_delete(offsets); offsets = NULL;
1826  cpl_table_delete(idscoeff); idscoeff = NULL;
1827 
1828  cpl_image_delete(norm_flat); norm_flat = NULL;
1829  cpl_vector_delete(lines); lines = NULL;
1830 
1831 
1832  cpl_msg_indent_less();
1833  cpl_msg_info(recipe,
1834  "Check object detection in both beams for all angles...");
1835  cpl_msg_indent_more();
1836 
1837  /*
1838  * House keeping - selection of objects for which information required
1839  * for Stokes parameters computation is present
1840  */
1841 
1842  error = mos_object_intersect(slitss, origslits, nscience, tolerance);
1843  if (error == CPL_ERROR_DATA_NOT_FOUND) {
1844  cpl_msg_warning(recipe, "No objects found: no Stokes "
1845  "parameters to compute!");
1846  for (j = 0; j < nscience; j++)
1847  cpl_table_delete(slitss[j]);
1848  cpl_free(slitss);
1849  cpl_table_delete(origslits);
1850  return 0;
1851  } else if (error) {
1852  fors_pmos_science_exit("Problem in polarimetric object selection", nscience);
1853  }
1854 
1855  fors_dfs_save_table(frameset, origslits, object_table_pol_tag,
1856  NULL, parlist, recipe, ref_sci_frame);
1857  if(cpl_error_get_code() != CPL_ERROR_NONE)
1858  fors_pmos_science_exit(NULL, nscience);
1859 
1860 
1861  /*
1862  * Save also object tables per angle after intersection
1863  */
1864 
1865  for (j = 0; j < nscience; j++) {
1866  if (!j) {
1867  if(dfs_save_image_null(frameset, parlist, object_table_tag,
1868  recipe, version)) {
1869  fors_pmos_science_exit(NULL, nscience);
1870  }
1871  }
1872 
1873  if (dfs_save_table_ext(slitss[j], object_table_tag, NULL)) {
1874  fors_pmos_science_exit(NULL, nscience);
1875  }
1876  }
1877 
1878  nobjs_per_slit = fors_get_nobjs_perslit(origslits);
1879 
1880  cpl_msg_indent_less();
1881  cpl_msg_info(recipe, "Object extraction...");
1882  cpl_msg_indent_more();
1883 
1884  for (j = 0; j < nscience; j++) {
1885  int k;
1886 
1887  header = dfs_load_header(frameset, science_tag, 0);
1888 
1889  for (k = 0; k < j; k ++) {
1890  cpl_propertylist_delete(header);
1891  header = dfs_load_header(frameset, NULL, 0);
1892  }
1893 
1894  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1895  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1896  cpl_propertylist_update_double(header, "CRVAL1",
1897  startwavelength + (dispersion * group)/2);
1898  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1899  cpl_propertylist_update_double(header, "CD1_1", dispersion * group);
1900  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1901  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1902  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1903  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1904  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1905 
1906  if (skymedian || skylocal) {
1907 
1908  cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...",
1909  angles[j], j + 1, nscience);
1910 
1911  images = mos_extract_objects(mappeds[j], NULL, skylocalmaps[j],
1912  origslits,
1913  ext_mode, ron, gain, 1);
1914 
1915  cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
1916 
1917  if (images) {
1918  if (time_normalise)
1919  cpl_image_divide_scalar(images[0], alltime);
1920 
1921  mos_rebin_signal(images, group);
1922 
1923  if (!j) {
1924  if(dfs_save_image_null(frameset, parlist,
1925  reduced_science_tag,
1926  recipe, version)) {
1927  fors_pmos_science_exit(NULL, nscience);
1928  }
1929  }
1930 
1931  if (dfs_save_image_ext(images[0], reduced_science_tag,
1932  header)) {
1933  fors_pmos_science_exit(NULL, nscience);
1934  }
1935 
1936  reduceds[j] = images[0];
1937 
1938  if (time_normalise)
1939  cpl_image_divide_scalar(images[1], alltime);
1940 
1941  mos_rebin_signal(images + 1, group);
1942 
1943  if (!j) {
1944  if(dfs_save_image_null(frameset, parlist,
1945  reduced_sky_tag,
1946  recipe, version)) {
1947  fors_pmos_science_exit(NULL, nscience);
1948  }
1949  }
1950 
1951  if (dfs_save_image_ext(images[1], reduced_sky_tag,
1952  header)) {
1953  fors_pmos_science_exit(NULL, nscience);
1954  }
1955  cpl_image_delete(images[1]);
1956 
1957  if (time_normalise)
1958  cpl_image_divide_scalar(images[2], alltime);
1959 
1960  mos_rebin_error(images + 2, group);
1961 
1962  if (!j) {
1963  if(dfs_save_image_null(frameset, parlist,
1964  reduced_error_tag,
1965  recipe, version)) {
1966  fors_pmos_science_exit(NULL, nscience);
1967  }
1968  }
1969 
1970  if (dfs_save_image_ext(images[2], reduced_error_tag,
1971  header)) {
1972  fors_pmos_science_exit(NULL, nscience);
1973  }
1974 
1975  rerrors[j] = images[2];
1976 
1977  cpl_free(images);
1978  }
1979  else {
1980  cpl_msg_warning(recipe, "No objects found: the products "
1981  "%s, %s, and %s are not created",
1982  reduced_science_tag, reduced_sky_tag,
1983  reduced_error_tag);
1984  }
1985 
1986  }
1987 
1988  if (skymedian || skylocal) {
1989  if (time_normalise)
1990  cpl_image_divide_scalar(mappeds[j], alltime);
1991 
1992  if (!j) {
1993  if(dfs_save_image_null(frameset, parlist,
1994  mapped_science_tag,
1995  recipe, version)) {
1996  fors_pmos_science_exit(NULL, nscience);
1997  }
1998  }
1999 
2000  if (dfs_save_image_ext(mappeds[j], mapped_science_tag,
2001  header)) {
2002  fors_pmos_science_exit(NULL, nscience);
2003  }
2004  }
2005 
2006  cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
2007  cpl_propertylist_delete(header); header = NULL;
2008 
2009  }
2010 
2011  cpl_table_delete(origslits);
2012 
2013  /* Stokes computation */
2014 
2015  nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
2016  nx = cpl_image_get_size_x(reduceds[0]);
2017 
2018  header = cpl_propertylist_new();
2019  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
2020  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
2021  cpl_propertylist_update_double(header, "CRVAL1",
2022  startwavelength + (dispersion * group)/2);
2023  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
2024  cpl_propertylist_update_double(header, "CD1_1", dispersion * group);
2025  cpl_propertylist_update_double(header, "CD1_2", 0.0);
2026  cpl_propertylist_update_double(header, "CD2_1", 0.0);
2027  cpl_propertylist_update_double(header, "CD2_2", 1.0);
2028  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
2029  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
2030 
2031  if (circ) {
2032 
2033  cpl_image *pv_im = NULL;
2034  cpl_image *pi_im = NULL;
2035  cpl_image *pvnull_im = NULL;
2036  cpl_image *pierr_im = NULL;
2037  cpl_image *perr_im = NULL;
2038 
2039  double *p_v = NULL;
2040  double *p_i = NULL;
2041  double *p_vnull = NULL;
2042  double *perr = NULL;
2043  double *pierr = NULL;
2044 
2045  double mean_vnull;
2046 
2047  int p = -1;
2048  int total = 0;
2049 
2050  pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2051  perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2052  pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2053  pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2054 
2055  p_v = cpl_image_get_data_double(pv_im);
2056  perr = cpl_image_get_data_double(perr_im);
2057  p_i = cpl_image_get_data_double(pi_im);
2058  pierr = cpl_image_get_data_double(pierr_im);
2059 
2060  if (nscience / 2 > 1) {
2061  pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2062  p_vnull = cpl_image_get_data_double(pvnull_im);
2063  }
2064 
2065  for (j = 0; j < nobjects; j++) {
2066 
2067  FILE *file; // Bagoo
2068  char *filename; // Bagoo
2069 
2070  int m;
2071 
2072  double * ip_v, * ip_i, * ipierr,
2073  * ip_vnull, * iperr;
2074 
2075  float * data;
2076  float * iff, * ierr;
2077 
2078  ip_v = p_v + (nobjects - 1 - j) * nx;
2079 
2080  if (nscience / 2 > 1)
2081  ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
2082 
2083  iperr = perr + (nobjects - 1 - j) * nx;
2084 
2085  ip_i = p_i + (nobjects - 1 - j) * nx;
2086  ipierr = pierr + (nobjects - 1 - j) * nx;
2087 
2088  total = 0;
2089  for (i = 0; i < nslits; i += 2) {
2090  total += nobjs_per_slit[i];
2091  if (total > j) {
2092  p = i;
2093  break;
2094  }
2095  }
2096 
2097  for (int k = 0; k < nscience / 2; k++) {
2098  float *if_o, *if_e, *ifdelta_o, *ifdelta_e;
2099  float *if_o_err, *if_e_err, *ifdelta_o_err, *ifdelta_e_err;
2100 
2101  int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45);
2102  int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
2103 
2104 
2105  data = cpl_image_get_data_float(reduceds[pos]);
2106 
2107  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2108  + (total - j - 1)) * nx;
2109 
2110  if_e = data + (2 * (nobjects - total)
2111  + (total - j - 1)) * nx;
2112 
2113  data = cpl_image_get_data_float(reduceds[pos_d]);
2114 
2115  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2116  + (total - j - 1)) * nx;
2117 
2118  ifdelta_e = data + (2 * (nobjects - total)
2119  + (total - j - 1)) * nx;
2120 
2121  data = cpl_image_get_data_float(rerrors[pos]);
2122 
2123  if_o_err = data
2124  + (2 * (nobjects - total) + nobjs_per_slit[p]
2125  + (total - j - 1)) * nx;
2126 
2127  if_e_err = data + (2 * (nobjects - total)
2128  + (total - j - 1)) * nx;
2129 
2130  data = cpl_image_get_data_float(rerrors[pos_d]);
2131 
2132  ifdelta_o_err = data
2133  + (2 * (nobjects - total) + nobjs_per_slit[p]
2134  + (total - j - 1)) * nx;
2135 
2136  ifdelta_e_err = data + (2 * (nobjects - total)
2137  + (total - j - 1)) * nx;
2138 
2139  if (bagoo) {
2140 
2141  char *signal_to_noise = getenv("SIGNAL_TO_NOISE" );
2142  float s2n = 100.;
2143  char *min_s2n = getenv("MIN_S2N" );
2144  int ms2n = 50;
2145 
2146  if (signal_to_noise)
2147  s2n = atof(signal_to_noise);
2148 
2149  if (min_s2n)
2150  ms2n = atoi(min_s2n);
2151 
2152  /*
2153  * Check whether S/N is > s2n in more than ms2n pixels
2154  * (on first frame, on ordinary beam)
2155  */
2156 
2157  if (k == 0) {
2158  bright = 0;
2159  for (m = 0; m < nx; m++) {
2160  if (if_o_err[m] > 0.0) {
2161  if (if_o[m]/if_o_err[m] > s2n) {
2162  bright++;
2163  if (bright > ms2n) {
2164  break;
2165  }
2166  }
2167  }
2168  }
2169  }
2170 
2171  if (bright > ms2n) {
2172  conta++;
2173  filename = cpl_sprintf("angle_%d_%d.dat",
2174  180*k-45, conta);
2175  file = fopen(filename, "w");
2176 
2177  fprintf(file, "%d\n", p + 2);
2178 
2179  for (m = 0; m < nx; m++) {
2180  double lambda = startwavelength
2181  + dispersion * group * (0.5 + m);
2182  fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n",
2183  lambda, if_o[m], if_o_err[m],
2184  if_e[m], if_e_err[m]);
2185  }
2186 
2187  fclose(file);
2188  cpl_free(filename);
2189 
2190  filename = cpl_sprintf("angle_%d_%d.dat",
2191  180*k+45, conta);
2192  file = fopen(filename, "w");
2193 
2194  fprintf(file, "%d\n", p + 2);
2195 
2196  for (m = 0; m < nx; m++) {
2197  double lambda = startwavelength
2198  + dispersion * group * (0.5 + m);
2199  fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n",
2200  lambda, ifdelta_o[m], ifdelta_o_err[m],
2201  ifdelta_e[m], ifdelta_e_err[m]);
2202  }
2203 
2204  fclose(file);
2205  cpl_free(filename);
2206  }
2207  else {
2208  cpl_msg_info(recipe,
2209  "Extracted signal not written to "
2210  "ASCII (S/N > %.0f only in %d < %d "
2211  "bins)", s2n, bright, ms2n);
2212  }
2213  } // End of bagoo
2214 
2215  for (m = 0; m < nx; m++) {
2216 
2217  double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
2218  (if_o[m] - if_e[m] ) /
2219  (if_o[m] + if_e[m] ) -
2220  (ifdelta_o[m] - ifdelta_e[m]) /
2221  (ifdelta_o[m] + ifdelta_e[m]);
2222 
2223  quantity = isfinite(quantity) ? quantity : 0.0;
2224 
2225  /* PQ map computation */
2226  ip_v[m] += quantity * 0.5 / (nscience / 2);
2227 
2228  /* PQnull map computation */
2229  if (nscience / 2 > 1) {
2230  if (k % 2)
2231  ip_vnull[m] += quantity * 0.5 / (nscience / 2);
2232  else
2233  ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
2234  }
2235 
2236  /* I map computation */
2237  ip_i[m] += (if_o[m] + if_e[m] +
2238  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2239 
2240  /* Variance map computation */
2241  ipierr[m] += (if_o_err[m] * if_o_err[m]
2242  + if_e_err[m] * if_e_err[m]
2243  + ifdelta_o_err[m] * ifdelta_o_err[m]
2244  + ifdelta_e_err[m] * ifdelta_e_err[m])
2245  / nscience / nscience;
2246 
2247  }
2248  }
2249 
2250  /* Error map */
2251  data = cpl_image_get_data_float(reduceds[0]);
2252  iff = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2253 
2254  data = cpl_image_get_data_float(rerrors[0]);
2255  ierr = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2256 
2257  for (m = 0; m < nx; m++)
2258  iperr[m] = iff[m] <= 0.0 ?
2259  0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
2260 
2261  if (nscience / 2 > 1) {
2262  float * weights;
2263  float max, sum, sum2, imean;
2264 
2265  int k;
2266 
2267  /* QC on U NULL */
2268  weights = cpl_malloc(sizeof(float) * nx);
2269 
2270  max = 0.0;
2271  for (k = 0; k < nx; k++) {
2272  if (max < iff[k]) max = iff[k];
2273  }
2274 
2275  for (k = 0; k < nx; k++) {
2276  weights[k] = iff[k] < 0.0 ?
2277  0.0 : iff[k] * iff[k] / (max * max);
2278  }
2279 
2280  sum = 0.0;
2281  sum2 = 0.0;
2282  for (k = 0; k < nx; k++) {
2283  sum += weights[k] * ip_vnull[k];
2284  sum2 += weights[k];
2285  }
2286 
2287  cpl_free(weights);
2288 
2289  imean = sum / sum2;
2290 
2291  mean_vnull += (imean - mean_vnull) / (j + 1.0);
2292  }
2293  }
2294 
2295  fors_dfs_save_image(frameset, pv_im, reduced_v_tag, header,
2296  parlist, recipe, ref_sci_frame);
2297  if(cpl_error_get_code() != CPL_ERROR_NONE)
2298  fors_pmos_science_exit(NULL, nscience);
2299 
2300  fors_dfs_save_image(frameset, pi_im, reduced_i_tag, header,
2301  parlist, recipe, ref_sci_frame);
2302  if(cpl_error_get_code() != CPL_ERROR_NONE)
2303  fors_pmos_science_exit(NULL, nscience);
2304 
2305  if (nscience / 2 > 1) {
2306  char *pipefile;
2307  char *keyname;
2308  cpl_propertylist *qheader;
2309 
2310  qheader = dfs_load_header(frameset, science_tag, 0);
2311  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
2312  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
2313  cpl_propertylist_update_double(qheader, "CRVAL1",
2314  startwavelength + (dispersion * group)/2);
2315  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
2316  cpl_propertylist_update_double(qheader, "CD1_1",
2317  dispersion * group);
2318  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
2319  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
2320  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
2321  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
2322  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
2323 
2324  if (qc) {
2325  fors_qc_start_group(qheader, "2.0", instrume);
2326 
2327  /*
2328  * QC1 group header
2329  */
2330 
2331  if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag,
2332  "Product category", instrume))
2333  fors_pmos_science_exit("Cannot write product category to "
2334  "QC log file", nscience);
2335 
2336  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
2337  "DPR type", instrume))
2338  fors_pmos_science_exit("Missing keyword DPR TYPE in "
2339  "scientific frame header", nscience);
2340 
2341  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
2342  "Template", instrume))
2343  fors_pmos_science_exit("Missing keyword TPL ID in "
2344  "scientific frame header", nscience);
2345 
2346  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
2347  "Grism name", instrume))
2348  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
2349  "scientific frame header", nscience);
2350 
2351  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
2352  "Grism identifier", instrume))
2353  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
2354  "scientific frame header", nscience);
2355 
2356  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
2357  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
2358  "Filter name", instrume);
2359 
2360  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
2361  "Collimator name", instrume))
2362  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
2363  "scientific frame header", nscience);
2364 
2365  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
2366  "Chip identifier", instrume))
2367  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
2368  "scientific frame header", nscience);
2369 
2370  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
2371  "Archive name of input data",
2372  instrume))
2373  fors_pmos_science_exit("Missing keyword ARCFILE in "
2374  "scientific frame header", nscience);
2375 
2376  pipefile = dfs_generate_filename(reduced_nul_v_tag);
2377  if (fors_qc_write_string("PIPEFILE", pipefile,
2378  "Pipeline product name", instrume))
2379  fors_pmos_science_exit("Cannot write PIPEFILE to "
2380  "QC log file", nscience);
2381  cpl_free(pipefile); pipefile = NULL;
2382 
2383 
2384  /*
2385  * QC1 parameters
2386  */
2387 
2388  keyname = "QC.NULL.V.MEAN";
2389 
2390  if (fors_qc_write_qc_double(qheader, mean_vnull,
2391  keyname, NULL,
2392  "Mean V null parameter",
2393  instrume)) {
2394  fors_pmos_science_exit("Cannot write mean Q null "
2395  "parameter to QC log file.", nscience);
2396  }
2397 
2398  keyname = "QC.NANGLES";
2399 
2400  if (fors_qc_write_qc_int(qheader, nscience,
2401  keyname, NULL,
2402  "Number of processed plate angles",
2403  instrume)) {
2404  fors_pmos_science_exit("Cannot write number of processed "
2405  "plate angles.", nscience);
2406  }
2407 
2409  }
2410 
2411  fors_dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader,
2412  parlist, recipe, ref_sci_frame);
2413  if(cpl_error_get_code() != CPL_ERROR_NONE)
2414  fors_pmos_science_exit(NULL, nscience);
2415 
2416  cpl_propertylist_delete(qheader);
2417  }
2418 
2419  fors_dfs_save_image(frameset, perr_im, reduced_error_v_tag, header,
2420  parlist, recipe, ref_sci_frame);
2421  if(cpl_error_get_code() != CPL_ERROR_NONE)
2422  fors_pmos_science_exit(NULL, nscience);
2423 
2424  cpl_image_power(pierr_im, 0.5);
2425 
2426  fors_dfs_save_image(frameset, pierr_im, reduced_error_i_tag, header,
2427  parlist, recipe, ref_sci_frame);
2428  if(cpl_error_get_code() != CPL_ERROR_NONE)
2429  fors_pmos_science_exit(NULL, nscience);
2430 
2431  cpl_image_delete(pv_im);
2432  cpl_image_delete(pvnull_im);
2433  cpl_image_delete(perr_im);
2434  cpl_image_delete(pi_im);
2435  cpl_image_delete(pierr_im);
2436  }
2437  else { /* Linear polarisation */
2438  cpl_image *pq_im = NULL;
2439  cpl_image *pu_im = NULL;
2440  cpl_image *pl_im = NULL;
2441  cpl_image *pi_im = NULL;
2442 
2443  cpl_image *pqnull_im = NULL;
2444  cpl_image *punull_im = NULL;
2445 
2446  cpl_image *pqerr_im = NULL;
2447  cpl_image *puerr_im = NULL;
2448  cpl_image *plerr_im = NULL;
2449  cpl_image *pierr_im = NULL;
2450 
2451  cpl_image *pang_im = NULL;
2452  cpl_image *pangerr_im = NULL;
2453 
2454  double *p_q = NULL;
2455  double *p_u = NULL;
2456  double *p_l = NULL;
2457  double *p_i = NULL;
2458 
2459  double *p_qnull = NULL;
2460  double *p_unull = NULL;
2461 
2462  double *pqerr = NULL;
2463  double *puerr = NULL;
2464  double *plerr = NULL;
2465  double *pierr = NULL;
2466 
2467  double *pang = NULL;
2468  double *pangerr = NULL;
2469 
2470  int m;
2471 
2472  cpl_image *correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
2473  double *correct = cpl_image_get_data_double(correct_im);
2474 
2475  double mean_unull, mean_qnull;
2476 
2477  int p = -1;
2478  int total = 0;
2479 
2480  pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2481  pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2482  pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2483  pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2484 
2485  pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2486  puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2487  plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2488  pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2489 
2490  pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2491  pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2492 
2493  p_q = cpl_image_get_data_double(pq_im);
2494  p_u = cpl_image_get_data_double(pu_im);
2495  p_l = cpl_image_get_data_double(pl_im);
2496  p_i = cpl_image_get_data_double(pi_im);
2497 
2498  if (nscience / 4 > 1) {
2499  pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2500  punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2501 
2502  p_qnull = cpl_image_get_data_double(pqnull_im);
2503  p_unull = cpl_image_get_data_double(punull_im);
2504  } else {
2505  cpl_msg_warning(cpl_func,
2506  "Not enough pairs to compute null parameters");
2507  }
2508 
2509  pqerr = cpl_image_get_data_double(pqerr_im);
2510  puerr = cpl_image_get_data_double(puerr_im);
2511  plerr = cpl_image_get_data_double(plerr_im);
2512  pierr = cpl_image_get_data_double(pierr_im);
2513 
2514  pang = cpl_image_get_data_double(pang_im);
2515  pangerr = cpl_image_get_data_double(pangerr_im);
2516 
2517  if (chromatism) {
2518  cpl_table * chrotbl =
2519  dfs_load_table(frameset, chrom_table_tag, 1);
2520 
2521  int nrow = cpl_table_get_nrow(chrotbl);
2522  float * lambda = cpl_table_get_data_float(chrotbl, "lambda");
2523  float * theta = cpl_table_get_data_float(chrotbl, "eps_theta");
2524 
2525  for (j = 0; j < nx; j++) {
2526  double c_wave = startwavelength
2527  + (dispersion * group) / 2
2528  + j * dispersion * group;
2529 
2530  int found = 0;
2531  int k;
2532 
2533  for (k = 0; k < nrow - 1; k++) {
2534  if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
2535  found = 1;
2536  break;
2537  }
2538  }
2539 
2540  if (found) {
2541  correct[j] = (theta [k + 1] - theta [k]) /
2542  (lambda[k + 1] - lambda[k]) *
2543  (c_wave - lambda[k]) + theta[k];
2544  correct[j] *= M_PI / 180; /* Radians */
2545  }
2546  else if (j)
2547  correct[j] = correct[j-1];
2548  else
2549  correct[j] = 0.0;
2550  }
2551 
2552  cpl_table_delete(chrotbl);
2553  }
2554 
2555  for (j = 0; j < nobjects; j++) {
2556  double *ip_q;
2557  double *ip_u;
2558  double *ip_l;
2559  double *ip_i;
2560  double *ipierr;
2561  double *ip_qnull;
2562  double *ip_unull;
2563  double *ipqerr;
2564  double *ipuerr;
2565  double *iplerr;
2566  double *ipang;
2567  double *ipangerr;
2568 
2569  float *data;
2570  float *iffq;
2571  float *ierrq;
2572  float *iffu;
2573  float *ierru;
2574 
2575  int pos, pos_d;
2576 
2577  ip_q = p_q + (nobjects - 1 - j) * nx;
2578  ip_u = p_u + (nobjects - 1 - j) * nx;
2579  ip_l = p_l + (nobjects - 1 - j) * nx;
2580  ip_i = p_i + (nobjects - 1 - j) * nx;
2581 
2582  if (nscience / 4 > 1) {
2583  ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
2584  ip_unull = p_unull + (nobjects - 1 - j) * nx;
2585  }
2586 
2587  ipqerr = pqerr + (nobjects - 1 - j) * nx;
2588  ipuerr = puerr + (nobjects - 1 - j) * nx;
2589  iplerr = plerr + (nobjects - 1 - j) * nx;
2590  ipierr = pierr + (nobjects - 1 - j) * nx;
2591 
2592  ipang = pang + (nobjects - 1 - j) * nx;
2593  ipangerr = pangerr + (nobjects - 1 - j) * nx;
2594 
2595  total = 0;
2596  for (i = 0; i < nslits; i += 2) {
2597  total += nobjs_per_slit[i];
2598  if (total > j) {
2599  p = i;
2600  break;
2601  }
2602  }
2603 
2604  for (int k = 0; k < nscience / 4; k++) {
2605  float * if_o, * if_e, * ifdelta_o, * ifdelta_e;
2606  float * if_o_err, * if_e_err, * ifdelta_o_err, * ifdelta_e_err;
2607 
2608  /* First P_Q */
2609 
2610  pos = fors_find_angle_pos(angles, nscience, 90 * k);
2611  pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
2612 
2613  data = cpl_image_get_data_float(reduceds[pos]);
2614 
2615  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2616  + (total - j - 1)) * nx;
2617 
2618  if_e = data + (2 * (nobjects - total)
2619  + (total - j - 1)) * nx;
2620 
2621  data = cpl_image_get_data_float(reduceds[pos_d]);
2622 
2623  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2624  + (total - j - 1)) * nx;
2625 
2626  ifdelta_e = data + (2 * (nobjects - total)
2627  + (total - j - 1)) * nx;
2628 
2629  data = cpl_image_get_data_float(rerrors[pos]);
2630 
2631  if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2632  + (total - j - 1)) * nx;
2633 
2634  if_e_err = data + (2 * (nobjects - total)
2635  + (total - j - 1)) * nx;
2636 
2637  data = cpl_image_get_data_float(rerrors[pos_d]);
2638 
2639  ifdelta_o_err = data + (2 * (nobjects - total)
2640  + nobjs_per_slit[p] + (total - j - 1)) * nx;
2641 
2642  ifdelta_e_err = data + (2 * (nobjects - total)
2643  + (total - j - 1)) * nx;
2644 
2645  for (m = 0; m < nx; m++) {
2646 
2647  double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2648  (if_o[m] - if_e[m] ) /
2649  (if_o[m] + if_e[m] ) -
2650  (ifdelta_o[m] - ifdelta_e[m]) /
2651  (ifdelta_o[m] + ifdelta_e[m]);
2652 
2653  quantity = isfinite(quantity) ? quantity : 0.0;
2654 
2655  /* PQ map computation */
2656  ip_q[m] += quantity * 0.5 / (nscience / 4);
2657 
2658  /* PQnull map computation */
2659  if (nscience / 4 > 1) {
2660  if (k % 2)
2661  ip_qnull[m] += quantity * 0.5 / (nscience / 4);
2662  else
2663  ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
2664  }
2665 
2666  /* I map computation */
2667  ip_i[m] += (if_o[m] + if_e[m] +
2668  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2669 
2670  /* Variance map computation */
2671  ipierr[m] += (if_o_err[m] * if_o_err[m]
2672  + if_e_err[m] * if_e_err[m]
2673  + ifdelta_o_err[m] * ifdelta_o_err[m]
2674  + ifdelta_e_err[m] * ifdelta_e_err[m])
2675  / nscience / nscience;
2676  }
2677 
2678  /* Now P_U */
2679 
2680  pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
2681  pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
2682 
2683  data = cpl_image_get_data_float(reduceds[pos]);
2684 
2685  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2686  + (total - j - 1)) * nx;
2687 
2688  if_e = data + (2 * (nobjects - total)
2689  + (total - j - 1)) * nx;
2690 
2691  data = cpl_image_get_data_float(reduceds[pos_d]);
2692 
2693  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2694  + (total - j - 1)) * nx;
2695 
2696  ifdelta_e = data + (2 * (nobjects - total)
2697  + (total - j - 1)) * nx;
2698 
2699  data = cpl_image_get_data_float(rerrors[pos]);
2700 
2701  if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2702  + (total - j - 1)) * nx;
2703 
2704  if_e_err = data + (2 * (nobjects - total)
2705  + (total - j - 1)) * nx;
2706 
2707  data = cpl_image_get_data_float(rerrors[pos_d]);
2708 
2709  ifdelta_o_err = data + (2 * (nobjects - total)
2710  + nobjs_per_slit[p] + (total - j - 1)) * nx;
2711 
2712  ifdelta_e_err = data + (2 * (nobjects - total)
2713  + (total - j - 1)) * nx;
2714 
2715  for (m = 0; m < nx; m++) {
2716 
2717  double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2718  (if_o[m] - if_e[m] ) /
2719  (if_o[m] + if_e[m] ) -
2720  (ifdelta_o[m] - ifdelta_e[m]) /
2721  (ifdelta_o[m] + ifdelta_e[m]);
2722 
2723  quantity = isfinite(quantity) ? quantity : 0.0;
2724 
2725  /* PU map computation */
2726  ip_u[m] += quantity * 0.5 / (nscience / 4);
2727 
2728  /* PUnull map computation */
2729  if (nscience / 4 > 1) {
2730  if (k % 2)
2731  ip_unull[m] += quantity * 0.5 / (nscience / 4);
2732  else
2733  ip_unull[m] -= quantity * 0.5 / (nscience / 4);
2734  }
2735 
2736  /* I map computation */
2737  ip_i[m] += (if_o[m] + if_e[m] +
2738  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2739 
2740  /* Variance map computation */
2741  ipierr[m] += (if_o_err[m] * if_o_err[m]
2742  + if_e_err[m] * if_e_err[m]
2743  + ifdelta_o_err[m] * ifdelta_o_err[m]
2744  + ifdelta_e_err[m] * ifdelta_e_err[m])
2745  / nscience / nscience;
2746  }
2747  }
2748 
2749  /* Error map */
2750 
2751  pos = fors_find_angle_pos(angles, nscience, 0.0);
2752 
2753  data = cpl_image_get_data_float(reduceds[pos]);
2754  iffq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2755 
2756  data = cpl_image_get_data_float(rerrors[pos]);
2757  ierrq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2758 
2759  pos = fors_find_angle_pos(angles, nscience, 22.5);
2760 
2761  data = cpl_image_get_data_float(reduceds[pos]);
2762  iffu = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2763 
2764  data = cpl_image_get_data_float(rerrors[pos]);
2765  ierru = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2766 
2767  for (m = 0; m < nx; m++) {
2768 
2769  double radicand;
2770 
2771  ipqerr[m] = iffq[m] <= 0.0 ?
2772  0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
2773 
2774  ipuerr[m] = iffu[m] <= 0.0 ?
2775  0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
2776 
2777  iplerr[m] = 0.5 * (ipqerr[m] + ipuerr[m]);
2778 
2779  /* PL computation */
2780  ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
2781 
2782  /* P angle computation */
2783  if (fabs(ip_q[m]) < 0.00001) {
2784  if (ip_u[m] > 0.0) {
2785  ipang[m] = 45.0;
2786  }
2787  else {
2788  ipang[m] = 135.0;
2789  }
2790  }
2791  else {
2792  ipang[m] = 0.5 * atan(ip_u[m] / ip_q[m]) * 180 / M_PI;
2793  if (ip_q[m] > 0.0) {
2794  if (ip_u[m] < 0.0) {
2795  ipang[m] += 180.;
2796  }
2797  }
2798  else {
2799  ipang[m] += 90.;
2800  }
2801  }
2802 
2803  /* Error on the angle computation */
2804  radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] +
2805  ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
2806 
2807  ipangerr[m] = (ip_l[m] == 0.0 ? 0.0 :
2808  sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI);
2809 
2810  /*
2811  * This is a quick and dirty patch for FORS2 had the
2812  * Wolly mounted +180 with respect to FORS1. I must
2813  * hardcode it, because there is no such info in the
2814  * header.
2815  */
2816 
2817  if (instrume[4] == '2') {
2818 
2819  double w_rotation = - wollaston * M_PI / 2;
2820 
2821  ipang[m] -= w_rotation * 180 / M_PI;
2822 
2823  ip_q[m] = ip_q[m] * cos(2 * w_rotation)
2824  + ip_u[m] * sin(2 * w_rotation);
2825 
2826  ip_u[m] = ip_u[m] * cos(2 * w_rotation)
2827  - ip_q[m] * sin(2 * w_rotation);
2828  }
2829 
2830  if (chromatism) {
2831  ipang[m] -= correct[m] * 180 / M_PI;
2832 
2833  ip_q[m] = ip_q[m] * cos(2 * correct[m])
2834  + ip_u[m] * sin(2 * correct[m]);
2835 
2836  ip_u[m] = ip_u[m] * cos(2 * correct[m])
2837  - ip_q[m] * sin(2 * correct[m]);
2838  }
2839 
2840  if (ipang[m] < 0.0)
2841  ipang[m] += 180.;
2842  else if (ipang[m] >= 180.0)
2843  ipang[m] -= 180.;
2844  }
2845 
2846  if (nscience / 4 > 1) {
2847  float * weights;
2848  float max, sum, sum2, imean;
2849 
2850  int k;
2851 
2852  /* QC on Q NULL */
2853  weights = cpl_malloc(sizeof(float) * nx);
2854 
2855  max = 0.0;
2856  for (k = 0; k < nx; k++) {
2857  if (max < iffq[k]) max = iffq[k];
2858  }
2859 
2860  for (k = 0; k < nx; k++) {
2861  weights[k] = iffq[k] < 0.0 ?
2862  0.0 : iffq[k] * iffq[k] / (max * max);
2863  }
2864 
2865  sum = 0.0;
2866  sum2 = 0.0;
2867  for (k = 0; k < nx; k++) {
2868  sum += weights[k] * ip_qnull[k];
2869  sum2 += weights[k];
2870  }
2871 
2872  cpl_free(weights);
2873 
2874  imean = sum / sum2;
2875 
2876  mean_qnull += (imean - mean_qnull) / (j + 1.0);
2877 
2878  /* QC on U NULL */
2879  weights = cpl_malloc(sizeof(float) * nx);
2880 
2881  max = 0.0;
2882  for (k = 0; k < nx; k++) {
2883  if (max < iffu[k]) max = iffu[k];
2884  }
2885 
2886  for (k = 0; k < nx; k++) {
2887  weights[k] = iffu[k] < 0.0 ?
2888  0.0 : iffu[k] * iffu[k] / (max * max);
2889  }
2890 
2891  sum = 0.0;
2892  sum2 = 0.0;
2893  for (k = 0; k < nx; k++) {
2894  sum += weights[k] * ip_unull[k];
2895  sum2 += weights[k];
2896  }
2897 
2898  cpl_free(weights);
2899 
2900  imean = sum / sum2;
2901 
2902  mean_unull += (imean - mean_unull) / (j + 1.0);
2903  }
2904  }
2905 
2906  cpl_image_delete(correct_im);
2907 
2908  fors_dfs_save_image(frameset, pq_im, reduced_q_tag, header,
2909  parlist, recipe, ref_sci_frame);
2910  if(cpl_error_get_code() != CPL_ERROR_NONE)
2911  fors_pmos_science_exit(NULL, nscience);
2912 
2913  fors_dfs_save_image(frameset, pu_im, reduced_u_tag, header,
2914  parlist, recipe, ref_sci_frame);
2915  if(cpl_error_get_code() != CPL_ERROR_NONE)
2916  fors_pmos_science_exit(NULL, nscience);
2917 
2918  if (qc && standard) {
2919  cpl_table *polsta = dfs_load_table(frameset, std_pmos_table_tag, 1);
2920  cpl_propertylist *qheader = dfs_load_header(frameset,
2921  science_tag, 0);
2922  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
2923  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
2924  cpl_propertylist_update_double(qheader, "CRVAL1",
2925  startwavelength + (dispersion * group)/2);
2926  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
2927  cpl_propertylist_update_double(qheader, "CD1_1",
2928  dispersion * group);
2929  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
2930  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
2931  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
2932  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
2933  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
2934 
2935  if (mos_check_polarisation(pq_im, pqerr_im, pu_im, puerr_im,
2936  startwavelength, dispersion, 1000.,
2937  polsta, ra, dec, &filter,
2938  &polarised,
2939  &qc_pl, &qc_pl_err,
2940  &qc_angle, &qc_angle_err)) {
2941  cpl_msg_warning(cpl_func, "No QC can be computed");
2942  }
2943  else {
2944  char *pipefile;
2945  char *keyname;
2946  char *text;
2947  char band[] = {' ', '\0'};
2948 
2949  fors_qc_start_group(qheader, "2.0", instrume);
2950 
2951  /*
2952  * QC1 group header
2953  */
2954 
2955  if (fors_qc_write_string("PRO.CATG", reduced_l_tag,
2956  "Product category", instrume))
2957  fors_pmos_science_exit("Cannot write product category to "
2958  "QC log file", nscience);
2959 
2960  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
2961  "DPR type", instrume))
2962  fors_pmos_science_exit("Missing keyword DPR TYPE in "
2963  "scientific frame header", nscience);
2964 
2965  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
2966  "Template", instrume))
2967  fors_pmos_science_exit("Missing keyword TPL ID in "
2968  "scientific frame header", nscience);
2969 
2970  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
2971  "Grism name", instrume))
2972  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
2973  "scientific frame header", nscience);
2974 
2975  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
2976  "Grism identifier", instrume))
2977  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
2978  "scientific frame header", nscience);
2979 
2980  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
2981  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
2982  "Filter name", instrume);
2983 
2984  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
2985  "Collimator name", instrume))
2986  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
2987  "scientific frame header", nscience);
2988 
2989  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
2990  "Chip identifier", instrume))
2991  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
2992  "scientific frame header", nscience);
2993 
2994  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
2995  "Archive name of input data",
2996  instrume))
2997  fors_pmos_science_exit("Missing keyword ARCFILE in "
2998  "scientific frame header", nscience);
2999 
3000  pipefile = dfs_generate_filename(reduced_nul_q_tag);
3001  if (fors_qc_write_string("PIPEFILE", pipefile,
3002  "Pipeline product name", instrume))
3003  fors_pmos_science_exit("Cannot write PIPEFILE to "
3004  "QC log file", nscience);
3005  cpl_free(pipefile); pipefile = NULL;
3006 
3007 
3008  /*
3009  * QC1 parameters
3010  */
3011 
3012  keyname = "QC.PMOS.BAND";
3013 
3014  band[0] = filter;
3015  if (fors_qc_write_qc_string(qheader, keyname, band,
3016  "Band where polarisation was "
3017  "measured", instrume)) {
3018  fors_pmos_science_exit("Cannot write QC.PMOS.BAND "
3019  "parameter to QC log file", nscience);
3020  }
3021 
3022  keyname = "QC.PMOS.POLARISED";
3023 
3024  if (fors_qc_write_qc_int(qheader, polarised, keyname, NULL,
3025  "Polarisation is expected (1 = yes, "
3026  "0 = no)", instrume)) {
3027  fors_pmos_science_exit("Cannot write QC.PMOS.POLARISED "
3028  "parameter to QC log file", nscience);
3029  }
3030 
3031  keyname = "QC.PMOS.L.OFFSET";
3032 
3033  if (polarised)
3034  text = "Linear polarisation relative offset";
3035  else
3036  text = "Linear polarisation offset";
3037 
3038  if (fors_qc_write_qc_double(qheader, qc_pl, keyname, NULL,
3039  text, instrume)) {
3040  fors_pmos_science_exit("Cannot write linear polarisation "
3041  "offset to QC log file", nscience);
3042  }
3043 
3044  keyname = "QC.PMOS.L.OFFSETERR";
3045 
3046  if (fors_qc_write_qc_double(qheader, qc_pl_err, keyname, NULL,
3047  "Error on linear polarisation offset",
3048  instrume)) {
3049  fors_pmos_science_exit("Cannot write linear polarisation "
3050  "offset error to QC log file", nscience);
3051  }
3052 
3053  if (polarised) {
3054  keyname = "QC.PMOS.ANGLE.OFFSET";
3055 
3056  if (fors_qc_write_qc_double(qheader, qc_angle, keyname, NULL,
3057  "Polarisation angle offset",
3058  instrume)) {
3059  fors_pmos_science_exit("Cannot write polarisation "
3060  "angle offset to QC log file", nscience);
3061  }
3062 
3063  keyname = "QC.PMOS.ANGLE.OFFSETERR";
3064 
3065  if (fors_qc_write_qc_double(qheader, qc_angle_err, keyname,
3066  NULL, "Error on polarisation "
3067  "angle offset", instrume)) {
3068  fors_pmos_science_exit("Cannot write polarisation "
3069  "angle offset error to QC "
3070  "log file", nscience);
3071  }
3072  }
3073 
3075  }
3076 
3077  fors_dfs_save_image(frameset, pl_im, reduced_l_tag, qheader,
3078  parlist, recipe, ref_sci_frame);
3079  if(cpl_error_get_code() != CPL_ERROR_NONE)
3080  fors_pmos_science_exit(NULL, nscience);
3081 
3082  cpl_propertylist_delete(qheader);
3083  }
3084  else {
3085  fors_dfs_save_image(frameset, pl_im, reduced_l_tag, header,
3086  parlist, recipe, ref_sci_frame);
3087  if(cpl_error_get_code() != CPL_ERROR_NONE)
3088  fors_pmos_science_exit(NULL, nscience);
3089  }
3090 
3091  if (nscience / 4 > 1) {
3092  char *pipefile;
3093  char *keyname;
3094  cpl_propertylist *qheader = dfs_load_header(frameset,
3095  science_tag, 0);
3096 
3097  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
3098  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
3099  cpl_propertylist_update_double(qheader, "CRVAL1",
3100  startwavelength + (dispersion * group)/2);
3101  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
3102  cpl_propertylist_update_double(qheader, "CD1_1",
3103  dispersion * group);
3104  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
3105  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
3106  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
3107  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
3108  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
3109 
3110  if (qc) {
3111  fors_qc_start_group(qheader, "2.0", instrume);
3112 
3113  /*
3114  * QC1 group header
3115  */
3116 
3117  if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag,
3118  "Product category", instrume))
3119  fors_pmos_science_exit("Cannot write product category to "
3120  "QC log file", nscience);
3121 
3122  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
3123  "DPR type", instrume))
3124  fors_pmos_science_exit("Missing keyword DPR TYPE in "
3125  "scientific frame header", nscience);
3126 
3127  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
3128  "Template", instrume))
3129  fors_pmos_science_exit("Missing keyword TPL ID in "
3130  "scientific frame header", nscience);
3131 
3132  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
3133  "Grism name", instrume))
3134  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
3135  "scientific frame header", nscience);
3136 
3137  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
3138  "Grism identifier", instrume))
3139  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
3140  "scientific frame header", nscience);
3141 
3142  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
3143  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
3144  "Filter name", instrume);
3145 
3146  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
3147  "Collimator name", instrume))
3148  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
3149  "scientific frame header", nscience);
3150 
3151  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
3152  "Chip identifier", instrume))
3153  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
3154  "scientific frame header", nscience);
3155 
3156  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
3157  "Archive name of input data",
3158  instrume))
3159  fors_pmos_science_exit("Missing keyword ARCFILE in "
3160  "scientific frame header", nscience);
3161 
3162  pipefile = dfs_generate_filename(reduced_nul_q_tag);
3163  if (fors_qc_write_string("PIPEFILE", pipefile,
3164  "Pipeline product name", instrume))
3165  fors_pmos_science_exit("Cannot write PIPEFILE to "
3166  "QC log file", nscience);
3167  cpl_free(pipefile); pipefile = NULL;
3168 
3169 
3170  /*
3171  * QC1 parameters
3172  */
3173 
3174  keyname = "QC.NULL.Q.MEAN";
3175 
3176  if (fors_qc_write_qc_double(qheader, mean_qnull,
3177  keyname, NULL,
3178  "Mean Q null parameter",
3179  instrume)) {
3180  fors_pmos_science_exit("Cannot write mean Q null "
3181  "parameter to QC log file", nscience);
3182  }
3183 
3184  keyname = "QC.NANGLES";
3185 
3186  if (fors_qc_write_qc_int(qheader, nscience / 2,
3187  keyname, NULL,
3188  "Number of processed plate angles",
3189  instrume)) {
3190  fors_pmos_science_exit("Cannot write number of processed "
3191  "plate angles.", nscience);
3192  }
3193 
3195  }
3196 
3197  fors_dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader,
3198  parlist, recipe, ref_sci_frame);
3199  if(cpl_error_get_code() != CPL_ERROR_NONE)
3200  fors_pmos_science_exit(NULL, nscience);
3201 
3202  cpl_propertylist_delete(qheader);
3203 
3204  qheader = dfs_load_header(frameset, science_tag, 0);
3205 
3206  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
3207  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
3208  cpl_propertylist_update_double(qheader, "CRVAL1",
3209  startwavelength + (dispersion * group)/2);
3210  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
3211  cpl_propertylist_update_double(qheader, "CD1_1",
3212  dispersion * group);
3213  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
3214  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
3215  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
3216  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
3217  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
3218 
3219  if (qc) {
3220  fors_qc_start_group(qheader, "2.0", instrume);
3221 
3222  /*
3223  * QC1 group header
3224  */
3225 
3226  if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag,
3227  "Product category", instrume))
3228  fors_pmos_science_exit("Cannot write product category to "
3229  "QC log file", nscience);
3230 
3231  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
3232  "DPR type", instrume))
3233  fors_pmos_science_exit("Missing keyword DPR TYPE in "
3234  "scientific frame header", nscience);
3235 
3236  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
3237  "Template", instrume))
3238  fors_pmos_science_exit("Missing keyword TPL ID in "
3239  "scientific frame header", nscience);
3240 
3241  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
3242  "Grism name", instrume))
3243  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
3244  "scientific frame header", nscience);
3245 
3246  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
3247  "Grism identifier", instrume))
3248  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
3249  "scientific frame header", nscience);
3250 
3251  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
3252  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
3253  "Filter name", instrume);
3254 
3255  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
3256  "Collimator name", instrume))
3257  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
3258  "scientific frame header", nscience);
3259 
3260  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
3261  "Chip identifier", instrume))
3262  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
3263  "scientific frame header", nscience);
3264 
3265  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
3266  "Archive name of input data",
3267  instrume))
3268  fors_pmos_science_exit("Missing keyword ARCFILE in "
3269  "scientific frame header", nscience);
3270 
3271  pipefile = dfs_generate_filename(reduced_nul_u_tag);
3272  if (fors_qc_write_string("PIPEFILE", pipefile,
3273  "Pipeline product name", instrume))
3274  fors_pmos_science_exit("Cannot write PIPEFILE to "
3275  "QC log file", nscience);
3276  cpl_free(pipefile); pipefile = NULL;
3277 
3278 
3279  /*
3280  * QC1 parameters
3281  */
3282 
3283  keyname = "QC.NULL.U.MEAN";
3284 
3285  if (fors_qc_write_qc_double(qheader, mean_unull,
3286  keyname, NULL,
3287  "Mean U null parameter",
3288  instrume)) {
3289  fors_pmos_science_exit("Cannot write mean U null "
3290  "parameter to QC log file", nscience);
3291  }
3292 
3293  keyname = "QC.NANGLES";
3294 
3295  if (fors_qc_write_qc_int(qheader, nscience / 2,
3296  keyname, NULL,
3297  "Number of processed plate angles",
3298  instrume)) {
3299  fors_pmos_science_exit("Cannot write number of processed "
3300  "plate angles.", nscience);
3301  }
3302 
3304  }
3305 
3306  fors_dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader,
3307  parlist, recipe, ref_sci_frame);
3308  if(cpl_error_get_code() != CPL_ERROR_NONE)
3309  fors_pmos_science_exit(NULL, nscience);
3310 
3311  cpl_propertylist_delete(qheader);
3312  }
3313 
3314  fors_dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header,
3315  parlist, recipe, ref_sci_frame);
3316  if(cpl_error_get_code() != CPL_ERROR_NONE)
3317  fors_pmos_science_exit(NULL, nscience);
3318 
3319  fors_dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header,
3320  parlist, recipe, ref_sci_frame);
3321  if(cpl_error_get_code() != CPL_ERROR_NONE)
3322  fors_pmos_science_exit(NULL, nscience);
3323 
3324  fors_dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header,
3325  parlist, recipe, ref_sci_frame);
3326  if(cpl_error_get_code() != CPL_ERROR_NONE)
3327  fors_pmos_science_exit(NULL, nscience);
3328 
3329  fors_dfs_save_image(frameset, pang_im, reduced_angle_tag, header,
3330  parlist, recipe, ref_sci_frame);
3331  if(cpl_error_get_code() != CPL_ERROR_NONE)
3332  fors_pmos_science_exit(NULL, nscience);
3333 
3334  fors_dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag,
3335  header, parlist, recipe, ref_sci_frame);
3336  if(cpl_error_get_code() != CPL_ERROR_NONE)
3337  fors_pmos_science_exit(NULL, nscience);
3338 
3339  fors_dfs_save_image(frameset, pi_im, reduced_i_tag,
3340  header, parlist, recipe, ref_sci_frame);
3341  if(cpl_error_get_code() != CPL_ERROR_NONE)
3342  fors_pmos_science_exit(NULL, nscience);
3343 
3344  cpl_image_power(pierr_im, 0.5);
3345 
3346  fors_dfs_save_image(frameset, pierr_im, reduced_error_i_tag,
3347  header, parlist, recipe, ref_sci_frame);
3348  if(cpl_error_get_code() != CPL_ERROR_NONE)
3349  fors_pmos_science_exit(NULL, nscience);
3350 
3351 /* %%% */
3352 
3353  cpl_image_delete(pq_im);
3354  cpl_image_delete(pu_im);
3355  cpl_image_delete(pl_im);
3356  cpl_image_delete(pi_im);
3357 
3358  cpl_image_delete(pqnull_im);
3359  cpl_image_delete(punull_im);
3360 
3361  cpl_image_delete(pqerr_im);
3362  cpl_image_delete(puerr_im);
3363  cpl_image_delete(plerr_im);
3364  cpl_image_delete(pierr_im);
3365  cpl_image_delete(pang_im);
3366  cpl_image_delete(pangerr_im);
3367  }
3368 
3369  cpl_propertylist_delete(header);
3370 
3371  /* End of Stokes computation */
3372 
3373  for (j = 0; j < nscience; j++) {
3374  cpl_image_delete(reduceds[j]);
3375  cpl_image_delete(rerrors[j]);
3376  cpl_table_delete(slitss[j]);
3377  cpl_image_delete(mappeds[j]);
3378  }
3379 
3380  cpl_free(reduceds);
3381  cpl_free(rerrors);
3382  cpl_free(slitss);
3383  cpl_free(mappeds);
3384 
3385  cpl_free(instrume); instrume = NULL;
3386 
3387  cpl_free(skylocalmaps);
3388 
3389  cpl_free(nobjs_per_slit);
3390 
3391  if (cpl_error_get_code()) {
3392  cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
3393  fors_pmos_science_exit(NULL, nscience);
3394  }
3395  else
3396  return 0;
3397 }
3398 
3399 /*----------------------------------------------------------------------------*/
3410 /*----------------------------------------------------------------------------*/
3411 static float * fors_check_angles(cpl_frameset * frameset,
3412  int pmos, const char *tag, int * circ)
3413 {
3414  float *angles = NULL;
3415  cpl_frame *c_frame = NULL;
3416  char *ret_id = NULL;
3417 
3418  int i = 0;
3419 
3420  angles = cpl_malloc(sizeof(float) * pmos);
3421 
3422  for (c_frame = cpl_frameset_find(frameset, tag);
3423  c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
3424 
3425  cpl_propertylist * header =
3426  cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
3427 
3428  if (!ret_id) {
3429  ret_id = cpl_strdup(cpl_propertylist_get_string(header,
3430  "ESO INS OPTI4 ID"));
3431 
3432  if (ret_id[1] != '5' && ret_id[1] != '4') {
3433  cpl_msg_error(cpl_func,
3434  "Unknown retarder plate id: %s", ret_id);
3435  return NULL;
3436  }
3437  } else {
3438  char * c_ret_id = (char *)
3439  cpl_propertylist_get_string(header, "ESO INS OPTI4 ID");
3440  if (ret_id[1] != c_ret_id[1]) {
3441  cpl_msg_error(cpl_func, "Input frames are not from the same "
3442  "retarder plate");
3443  return NULL;
3444  }
3445  }
3446 
3447  if (ret_id[1] == '5') { /* Linear polarimetry */
3448  if (cpl_propertylist_has(header, "ESO INS RETA2 ROT")) {
3449  angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3450  "ESO INS RETA2 ROT") + 0.5)/2;
3451  }
3452  else if (cpl_propertylist_has(header, "ESO INS RETA2 POSANG")) {
3453  if (cpl_propertylist_has(header, "ESO ADA POSANG")) {
3454  double reta2pos = cpl_propertylist_get_double(header,
3455  "ESO INS RETA2 POSANG");
3456  double adapos = cpl_propertylist_get_double(header,
3457  "ESO ADA POSANG");
3458  angles[i] = (float)floor(2*(reta2pos - adapos) + 0.5)/2;
3459  }
3460  else {
3461  cpl_msg_error(cpl_func,
3462  "ESO ADA POSANG not found in header");
3463  return NULL;
3464  }
3465  }
3466  else {
3467  cpl_msg_error(cpl_func, "Neither ESO INS RETA2 ROT nor "
3468  "ESO INS RETA2 POSANG found in header");
3469  return NULL;
3470  }
3471  *circ = 0;
3472  } else { /* Circular polarimetry */
3473  if (cpl_propertylist_has(header, "ESO INS RETA4 ROT")) {
3474  angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3475  "ESO INS RETA4 ROT") + 0.5)/2;
3476  //Check if it makes sense. Change in all other places
3477  if (angles[i] < 0)
3478  angles[i] = angles[i] + 360;
3479  }
3480  else if (cpl_propertylist_has(header, "ESO INS RETA4 POSANG")) {
3481  if (cpl_propertylist_has(header, "ESO ADA POSANG")) {
3482  double reta4pos = cpl_propertylist_get_double(header,
3483  "ESO INS RETA4 POSANG");
3484  double adapos = cpl_propertylist_get_double(header,
3485  "ESO ADA POSANG");
3486  angles[i] = (float)floor(2*(reta4pos - adapos) + 0.5/2);
3487  }
3488  else {
3489  cpl_msg_error(cpl_func,
3490  "ESO ADA POSANG not found in header");
3491  return NULL;
3492  }
3493  }
3494  else {
3495  cpl_msg_error(cpl_func, "Neither ESO INS RETA4 ROT nor "
3496  "ESO INS RETA4 POSANG found in header");
3497  return NULL;
3498  }
3499  *circ = 1;
3500  }
3501 
3502  cpl_propertylist_delete(header);
3503  i++;
3504  }
3505 
3506  cpl_free(ret_id);
3507 
3508  if (*circ) {
3509  if (pmos != 2 && pmos != 4) {
3510  cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
3511  "found, but either 2 or 4 are required for "
3512  "circular polarization measurements!", pmos);
3513  return NULL;
3514  }
3515  } else {
3516  if (pmos != 4 && pmos != 8 && pmos != 16) {
3517  cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
3518  "found, but either 4, 8, or 16 are required for "
3519  "linear polarization measurements!", pmos);
3520  return NULL;
3521  }
3522  }
3523 
3524  /* Check completeness */
3525 
3526  if (*circ) {
3527  for (i = 0; i < pmos; i++) {
3528  if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
3529  const char *cangles;
3530  switch (pmos) {
3531  case 2: cangles = "-45.0, 45.0"; break;
3532  case 4: cangles = "-45.0, 45.0, 135.0, 225.0"; break;
3533  default: assert(0);
3534  }
3535 
3536  cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
3537  "angle %.2f. All angles %s must be provided.",
3538  angles[i], cangles);
3539  return NULL;
3540  }
3541  }
3542  }
3543  else {
3544  for (i = 0; i < pmos; i++) {
3545  if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
3546  const char *cangles;
3547  switch (pmos) {
3548  case 4: cangles = "0.0, 22.5, 45.0, 67.5"; break;
3549  case 8: cangles = "0.0, 22.5, 45.0, 67.5, "
3550  "90.0, 112.5, 135.0, 157.5"; break;
3551  case 16: cangles = "0.0, 22.5, 45.0, 67.5, "
3552  "90.0, 112.5, 135.0, 157.5, "
3553  "180.0, 202.5, 225.0, 247.5, "
3554  "270.0, 292.5, 315.0, 337.5"; break;
3555  default: assert(0);
3556  }
3557 
3558  cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
3559  "angle %.2f. All angles %s must be provided.",
3560  angles[i], cangles);
3561  return NULL;
3562  }
3563  }
3564  }
3565 
3566  return angles;
3567 }
3568 
3569 /*----------------------------------------------------------------------------*/
3577 /*----------------------------------------------------------------------------*/
3578 static int
3579 fors_find_angle_pos(float * angles, int nangles, float angle)
3580 {
3581  int i, match = 0;
3582 
3583  for (i = 0; i < nangles; i++) {
3584  if (fabs(angles[i] - angle) < 1.0 ||
3585  fabs(angles[i] - 360.0 - angle) < 1.0) {
3586  match = 1;
3587  break;
3588  }
3589  }
3590 
3591  return match ? i : -1;
3592 }
3593 
cpl_image * mos_spatial_calibration(cpl_image *spectra, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion, int flux, cpl_image *calibration)
Spatial remapping of CCD spectra eliminating the spectral curvature.
Definition: moses.c:8540
cpl_error_code fors_qc_write_qc_string(cpl_propertylist *header, const char *name, const char *value, const char *comment, const char *instrument)
Write a string value to the active QC1 PAF object and to a header.
Definition: fors_qc.c:535
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: fors_bias.c:62
cpl_image * dfs_load_image(cpl_frameset *frameset, const char *category, cpl_type type, int ext, int calib)
Loading image data of given category.
Definition: fors_dfs.c:853
const char * dfs_get_parameter_string(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe string parameter value.
Definition: fors_dfs.c:599
double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines, double wavestart, double dispersion, int radius, int highres)
Estimate the spectral distortion modeling goodness.
Definition: moses.c:11077
cpl_propertylist * dfs_load_header(cpl_frameset *frameset, const char *category, int ext)
Loading header associated to data of given category.
Definition: fors_dfs.c:957
cpl_error_code dfs_save_image_null(cpl_frameset *frameset, cpl_parameterlist *parlist, const char *tag, const char *recipename, const char *version)
Save a product with an empty primary extension.
Definition: fors_dfs.c:1886
cpl_error_code dfs_save_image_ext(cpl_image *image, const char *tag, cpl_propertylist *extheader)
Save an image in a extension.
Definition: fors_dfs.c:1843
void fors_dfs_save_image(cpl_frameset *frameset, const cpl_image *image, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const cpl_frame *inherit_frame)
Save DFS product (image)
Definition: fors_dfs.c:1142
cpl_error_code fors_qc_write_qc_double(cpl_propertylist *header, double value, const char *name, const char *unit, const char *comment, const char *instrument)
Write an integer value to the active QC1 PAF object and to a header.
Definition: fors_qc.c:604
cpl_image * mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Remapping of spatially rectified wavelengths to original CCD pixels.
Definition: moses.c:11410
cpl_error_code fors_qc_keyword_to_paf(cpl_propertylist *header, const char *name, const char *unit, const char *comment, const char *instrument)
Copy a keyword value to the currently active QC1 PAF object.
Definition: fors_qc.c:425
cpl_image * mos_wavelength_calibration(cpl_image *image, double refwave, double firstLambda, double lastLambda, double dispersion, cpl_table *idscoeff, int flux)
Remap at constant wavelength step an image of rectified scientific spectra.
Definition: moses.c:9727
cpl_table * mos_load_slits_fors_mos(cpl_propertylist *header, int *nslits_out_det)
Create slit location table from FITS header of FORS1/2 MOS data.
Definition: moses.c:15143
cpl_table * mos_wavelength_align(cpl_image *image, cpl_table *slits, double refwave, double firstLambda, double lastLambda, cpl_table *idscoeff, cpl_vector *skylines, int highres, int order, cpl_image *calibration, int sradius)
Modify the input wavelength solution to match reference sky lines.
Definition: moses.c:10016
cpl_error_code fors_qc_start_group(cpl_propertylist *header, const char *qcdic_version, const char *instrument)
Initiate a new QC1 group.
Definition: fors_qc.c:77
cpl_image * mos_remove_bias(cpl_image *image, cpl_image *bias, cpl_table *overscans)
Subtract the bias from a CCD exposure.
Definition: moses.c:3654
cpl_error_code fors_qc_write_string(const char *name, const char *value, const char *comment, const char *instrument)
Add string parameter to current QC1 group.
Definition: fors_qc.c:235
cpl_image * mos_detect_objects(cpl_image *image, cpl_table *slits, int margin, int maxradius, int conradius)
Detect objects in rectified scientific frame.
Definition: moses.c:13974
cpl_image * mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
Local determination of sky.
Definition: moses.c:12747
void fors_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: fors_dfs.c:257
int dfs_get_parameter_bool(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe boolean parameter value.
Definition: fors_dfs.c:696
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
Definition: fors_dfs.c:1676
int mos_check_polarisation(cpl_image *q_image, cpl_image *q_error, cpl_image *u_image, cpl_image *u_error, double startwave, double dispersion, double band, cpl_table *pol_sta, double ra, double dec, char *filter, int *polarisation, double *p_offset, double *p_error, double *a_offset, double *a_error)
Estimate linear polarisation parameters on spectral interval.
Definition: moses.c:18405
cpl_error_code dfs_save_table_ext(cpl_table *table, const char *tag, cpl_propertylist *extheader)
Save a table in a extension (different from the first one)
Definition: fors_dfs.c:1804
void fors_dfs_save_table(cpl_frameset *frameset, const cpl_table *table, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const cpl_frame *inherit_frame)
Save DFS product (table)
Definition: fors_dfs.c:1400
cpl_error_code mos_object_intersect(cpl_table **slitss, cpl_table *origslits, int nscience, float tolerance)
Intersect a number of slit tables.
Definition: moses.c:16458
cpl_image * mos_subtract_sky(cpl_image *science, cpl_table *slits, cpl_table *polytraces, double reference, double blue, double red, double dispersion)
Subtract the sky from the scientific CCD exposure.
Definition: moses.c:1972
cpl_image * mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference, double blue, double red)
Create a wavelengths map from an IDS coefficients table.
Definition: moses.c:11299
cpl_table * dfs_load_table(cpl_frameset *frameset, const char *category, int ext)
Loading table data of given category.
Definition: fors_dfs.c:909
int dfs_get_parameter_int(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe integer parameter value.
Definition: fors_dfs.c:408
cpl_error_code fors_qc_end_group(void)
Close current QC1 PAF file.
Definition: fors_qc.c:200
cpl_image ** mos_extract_objects(cpl_image *science, cpl_image *science_var, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
Definition: moses.c:14325
cpl_error_code mos_clean_cosmics(cpl_image *image, float gain, float threshold, float ratio)
Remove cosmic rays from sky-subtracted CCD spectral exposure.
Definition: moses.c:13204
cpl_error_code mos_randomise_image(cpl_image *image, double ron, double gain, double bias)
Randomise image.
Definition: moses.c:16224
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.
Definition: fors_dfs.c:503