FORS Pipeline Reference Manual  5.3.8
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  if (flatfield) {
1444 
1445  if (norm_flat) {
1446  cpl_msg_info(recipe, "Apply flat field correction...");
1447  if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
1448  cpl_msg_error(recipe,
1449  "Failure of flat field correction: %s",
1450  cpl_error_get_message());
1451  fors_pmos_science_exit(NULL, nscience);
1452  }
1453  }
1454  else {
1455  cpl_msg_error(recipe, "Cannot load input %s for flat field "
1456  "correction", master_norm_flat_tag);
1457  fors_pmos_science_exit(NULL, nscience);
1458  }
1459 
1460  }
1461 
1462  /*
1463  * Load the spectral curvature table
1464  */
1465 
1466  polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
1467  if (polytraces == NULL)
1468  fors_pmos_science_exit("Cannot load spectral curvature table", nscience);
1469 
1470  /*
1471  * Load the slit location table
1472  */
1473 
1474  slits = dfs_load_table(frameset, slit_location_tag, 1);
1475  if (slits == NULL)
1476  fors_pmos_science_exit("Cannot load slits location table", nscience);
1477 
1478  cpl_msg_info(recipe, "Processing scientific spectra...");
1479 
1480  /*
1481  * This one will also generate the spatial map from the spectral
1482  * curvature table (in the case of multislit data)
1483  */
1484 
1485  coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1486 
1487  smapped = mos_spatial_calibration(spectra, slits, polytraces,
1488  reference, startwavelength,
1489  endwavelength, dispersion,
1490  flux, coordinate);
1491 
1492  /*
1493  * Generate a rectified wavelength map from the wavelength calibration
1494  * table
1495  */
1496 
1497  rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
1498  endwavelength);
1499 
1500  if (dispersion > 1.0)
1501  highres = 0;
1502  else
1503  highres = 1;
1504 
1505  if (skyalign >= 0) {
1506  if (skyalign) {
1507  cpl_msg_info(recipe,
1508  "Align wavelength solution to reference skylines "
1509  "applying %d order residual fit...", skyalign);
1510  }
1511  else {
1512  cpl_msg_info(recipe, "Align wavelength solution to reference "
1513  "skylines applying median offset...");
1514  }
1515 
1516  if (!j) {
1517  offsets = mos_wavelength_align(smapped, slits, reference,
1518  startwavelength, endwavelength,
1519  idscoeff, lines, highres,
1520  skyalign, rainbow, 4);
1521  if (offsets) {
1522  if (standard)
1523  cpl_msg_warning(recipe, "Alignment of the wavelength "
1524  "solution to reference sky lines may "
1525  "be unreliable in this case!");
1526 
1527  fors_dfs_save_table(frameset, offsets,
1528  skylines_offsets_tag, NULL,
1529  parlist, recipe, ref_sci_frame);
1530  if(cpl_error_get_code() != CPL_ERROR_NONE)
1531  fors_pmos_science_exit(NULL, nscience);
1532 
1533  } else {
1534  cpl_msg_warning(recipe, "Alignment of the wavelength "
1535  "solution to reference sky lines could "
1536  "not be done!");
1537  skyalign = -1;
1538  }
1539  }
1540 
1541 
1542  }
1543 
1544  wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
1545  polytraces, reference,
1546  startwavelength, endwavelength,
1547  dispersion);
1548 
1549 
1550  cpl_image_delete(rainbow); rainbow = NULL;
1551  cpl_image_delete(coordinate); coordinate = NULL;
1552 
1553  /*
1554  * Here the wavelength calibrated slit spectra are created. This frame
1555  * contains sky_science.
1556  */
1557 
1558  mapped_sky = mos_wavelength_calibration(smapped, reference,
1559  startwavelength, endwavelength,
1560  dispersion, idscoeff, flux);
1561 
1562  if (!j) {
1563  cpl_msg_indent_less();
1564  cpl_msg_info(recipe,
1565  "Check applied wavelength against skylines...");
1566  cpl_msg_indent_more();
1567 
1568  mean_rms = mos_distortions_rms(mapped_sky, lines, startwavelength,
1569  dispersion, 6, highres);
1570 
1571 
1572  cpl_msg_info(recipe, "Mean residual: %f", mean_rms);
1573 
1574  mean_rms = cpl_table_get_column_mean(idscoeff, "error");
1575 
1576  cpl_msg_info(recipe, "Mean model accuracy: %f pixel (%f A)",
1577  mean_rms, mean_rms * dispersion);
1578  }
1579 
1580  save_header = cpl_propertylist_duplicate(header);
1581 
1582  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1583  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1584  cpl_propertylist_update_double(header, "CRVAL1",
1585  startwavelength + dispersion/2);
1586  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1587  cpl_propertylist_update_double(header, "CD1_1", dispersion);
1588  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1589  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1590  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1591  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1592  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1593 
1594  if (time_normalise) {
1595  dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
1596 
1597  if (!j) {
1598  if(dfs_save_image_null(frameset, parlist,
1599  mapped_science_sky_tag,
1600  recipe, version)) {
1601  fors_pmos_science_exit(NULL, nscience);
1602  }
1603  }
1604 
1605  if (dfs_save_image_ext(dummy, mapped_science_sky_tag, header)) {
1606  fors_pmos_science_exit(NULL, nscience);
1607  }
1608 
1609  cpl_image_delete(dummy); dummy = NULL;
1610  }
1611  else {
1612 
1613  if (!j) {
1614  if(dfs_save_image_null(frameset, parlist,
1615  mapped_science_sky_tag,
1616  recipe, version)) {
1617  fors_pmos_science_exit(NULL, nscience);
1618  }
1619  }
1620 
1621  if (dfs_save_image_ext(mapped_sky,
1622  mapped_science_sky_tag, header)) {
1623  fors_pmos_science_exit(NULL, nscience);
1624  }
1625 
1626  }
1627 
1628  if (skymedian == 0 && skylocal == 0) {
1629  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1630  }
1631 
1632  if (skylocal) {
1633 
1634  cpl_msg_indent_less();
1635 
1636  cpl_msg_info(recipe, "Local sky determination...");
1637  cpl_msg_indent_more();
1638  skymap = mos_subtract_sky(spectra, slits, polytraces, reference,
1639  startwavelength, endwavelength, dispersion);
1640 
1641  if (skymap) {
1642  if (time_normalise)
1643  cpl_image_divide_scalar(skymap, alltime);
1644 
1645  if (!j) {
1646  if(dfs_save_image_null(frameset, parlist,
1647  unmapped_sky_tag,
1648  recipe, version)) {
1649  fors_pmos_science_exit(NULL, nscience);
1650  }
1651  }
1652 
1653  if (dfs_save_image_ext(skymap, unmapped_sky_tag,
1654  save_header)) {
1655  fors_pmos_science_exit(NULL, nscience);
1656  }
1657 
1658  cpl_image_delete(skymap); skymap = NULL;
1659 
1660  if (!j) {
1661  if(dfs_save_image_null(frameset, parlist,
1662  unmapped_science_tag,
1663  recipe, version)) {
1664  fors_pmos_science_exit(NULL, nscience);
1665  }
1666  }
1667 
1668  if (dfs_save_image_ext(spectra, unmapped_science_tag,
1669  save_header)) {
1670  fors_pmos_science_exit(NULL, nscience);
1671  }
1672 
1673  if (cosmics) {
1674  cpl_msg_info(recipe, "Removing cosmic rays...");
1675  mos_clean_cosmics(spectra, gain, -1., -1.);
1676  }
1677 
1678  /*
1679  * The spatially rectified image, that contained the sky,
1680  * is replaced by a sky-subtracted spatially rectified image:
1681  */
1682 
1683  cpl_image_delete(smapped); smapped = NULL;
1684 
1685  smapped = mos_spatial_calibration(spectra, slits, polytraces,
1686  reference, startwavelength,
1687  endwavelength, dispersion,
1688  flux, NULL);
1689  }
1690  else {
1691  cpl_msg_warning(recipe, "Sky subtraction failure");
1692  if (cosmics)
1693  cpl_msg_warning(recipe,
1694  "Cosmic rays removal not performed!");
1695  cosmics = skylocal = 0;
1696  }
1697  }
1698 
1699  cpl_image_delete(spectra); spectra = NULL;
1700  cpl_table_delete(polytraces); polytraces = NULL;
1701 
1702  if (skyalign >= 0) {
1703  save_header = dfs_load_header(frameset, science_tag, 0);
1704 
1705  if (!j) {
1706  if(dfs_save_image_null(frameset, parlist,
1707  wavelength_map_sky_tag,
1708  recipe, version)) {
1709  fors_pmos_science_exit(NULL, nscience);
1710  }
1711  }
1712 
1713  if (dfs_save_image_ext(wavemap, wavelength_map_sky_tag,
1714  save_header)) {
1715  fors_pmos_science_exit(NULL, nscience);
1716  }
1717  }
1718 
1719  cpl_image_delete(wavemap); wavemap = NULL;
1720 
1721  mapped = mos_wavelength_calibration(smapped, reference,
1722  startwavelength, endwavelength,
1723  dispersion, idscoeff, flux);
1724 
1725  cpl_image_delete(smapped); smapped = NULL;
1726 
1727  if (skyalign >= 0) {
1728  if (!j) {
1729  fors_dfs_save_table(frameset, idscoeff, disp_coeff_sky_tag,
1730  NULL, parlist, recipe, ref_sci_frame);
1731  if(cpl_error_get_code() != CPL_ERROR_NONE)
1732  fors_pmos_science_exit(NULL, nscience);
1733  }
1734  }
1735 
1736  if (skymedian) {
1737  cpl_msg_indent_less();
1738  cpl_msg_info(recipe, "Local sky determination...");
1739  cpl_msg_indent_more();
1740 
1741  skylocalmap = mos_sky_local_old(mapped, slits);
1742  cpl_image_subtract(mapped, skylocalmap);
1743  cpl_image_delete(skylocalmap); skylocalmap = NULL;
1744  }
1745 
1746  if (skymedian || skylocal) {
1747 
1748  skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
1749 
1750  cpl_image_delete(mapped_sky); mapped_sky = NULL;
1751 
1752  if (time_normalise) {
1753  dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
1754 
1755  if (!j) {
1756  if(dfs_save_image_null(frameset, parlist,
1757  mapped_sky_tag,
1758  recipe, version)) {
1759  fors_pmos_science_exit(NULL, nscience);
1760  }
1761  }
1762 
1763  if (dfs_save_image_ext(dummy, mapped_sky_tag,
1764  header)) {
1765  fors_pmos_science_exit(NULL, nscience);
1766  }
1767 
1768  cpl_image_delete(dummy); dummy = NULL;
1769  }
1770  else {
1771  if (!j) {
1772  if(dfs_save_image_null(frameset, parlist,
1773  mapped_sky_tag,
1774  recipe, version)) {
1775  fors_pmos_science_exit(NULL, nscience);
1776  }
1777  }
1778 
1779  if (dfs_save_image_ext(skylocalmap, mapped_sky_tag,
1780  header)) {
1781  fors_pmos_science_exit(NULL, nscience);
1782  }
1783  }
1784 
1785  skylocalmaps[j] = skylocalmap;
1786 
1787  cpl_msg_indent_less();
1788  cpl_msg_info(recipe, "Object detection...");
1789  cpl_msg_indent_more();
1790 
1791  if (!j) {
1792  origslits = cpl_table_duplicate(slits);
1793  nslits = cpl_table_get_nrow(slits);
1794  }
1795 
1796  if (cosmics || nscience > 1) {
1797  dummy = mos_detect_objects(mapped, slits, slit_margin,
1798  ext_radius, cont_radius);
1799  }
1800  else {
1801  mapped_cleaned = cpl_image_duplicate(mapped);
1802  mos_clean_cosmics(mapped_cleaned, gain, -1., -1.);
1803  dummy = mos_detect_objects(mapped_cleaned, slits, slit_margin,
1804  ext_radius, cont_radius);
1805 
1806  cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
1807  }
1808 
1809  cpl_image_delete(dummy); dummy = NULL;
1810 
1811  }
1812 
1813  slitss[j] = slits;
1814  mappeds[j] = mapped;
1815 
1816  cpl_msg_indent_less();
1817 
1818  cpl_propertylist_delete(header); header = NULL;
1819  cpl_propertylist_delete(save_header); save_header = NULL;
1820  }
1821 
1822  cpl_table_delete(offsets); offsets = NULL;
1823  cpl_table_delete(idscoeff); idscoeff = NULL;
1824 
1825  cpl_image_delete(norm_flat); norm_flat = NULL;
1826  cpl_vector_delete(lines); lines = NULL;
1827 
1828 
1829  cpl_msg_indent_less();
1830  cpl_msg_info(recipe,
1831  "Check object detection in both beams for all angles...");
1832  cpl_msg_indent_more();
1833 
1834  /*
1835  * House keeping - selection of objects for which information required
1836  * for Stokes parameters computation is present
1837  */
1838 
1839  error = mos_object_intersect(slitss, origslits, nscience, tolerance);
1840  if (error == CPL_ERROR_DATA_NOT_FOUND) {
1841  cpl_msg_warning(recipe, "No objects found: no Stokes "
1842  "parameters to compute!");
1843  for (j = 0; j < nscience; j++)
1844  cpl_table_delete(slitss[j]);
1845  cpl_free(slitss);
1846  cpl_table_delete(origslits);
1847  return 0;
1848  } else if (error) {
1849  fors_pmos_science_exit("Problem in polarimetric object selection", nscience);
1850  }
1851 
1852  fors_dfs_save_table(frameset, origslits, object_table_pol_tag,
1853  NULL, parlist, recipe, ref_sci_frame);
1854  if(cpl_error_get_code() != CPL_ERROR_NONE)
1855  fors_pmos_science_exit(NULL, nscience);
1856 
1857 
1858  /*
1859  * Save also object tables per angle after intersection
1860  */
1861 
1862  for (j = 0; j < nscience; j++) {
1863  if (!j) {
1864  if(dfs_save_image_null(frameset, parlist, object_table_tag,
1865  recipe, version)) {
1866  fors_pmos_science_exit(NULL, nscience);
1867  }
1868  }
1869 
1870  if (dfs_save_table_ext(slitss[j], object_table_tag, NULL)) {
1871  fors_pmos_science_exit(NULL, nscience);
1872  }
1873  }
1874 
1875  nobjs_per_slit = fors_get_nobjs_perslit(origslits);
1876 
1877  cpl_msg_indent_less();
1878  cpl_msg_info(recipe, "Object extraction...");
1879  cpl_msg_indent_more();
1880 
1881  for (j = 0; j < nscience; j++) {
1882  int k;
1883 
1884  header = dfs_load_header(frameset, science_tag, 0);
1885 
1886  for (k = 0; k < j; k ++) {
1887  cpl_propertylist_delete(header);
1888  header = dfs_load_header(frameset, NULL, 0);
1889  }
1890 
1891  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
1892  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
1893  cpl_propertylist_update_double(header, "CRVAL1",
1894  startwavelength + (dispersion * group)/2);
1895  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
1896  cpl_propertylist_update_double(header, "CD1_1", dispersion * group);
1897  cpl_propertylist_update_double(header, "CD1_2", 0.0);
1898  cpl_propertylist_update_double(header, "CD2_1", 0.0);
1899  cpl_propertylist_update_double(header, "CD2_2", 1.0);
1900  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
1901  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
1902 
1903  if (skymedian || skylocal) {
1904 
1905  cpl_msg_info(recipe, "Extracting at angle %.2f (%d out of %d) ...",
1906  angles[j], j + 1, nscience);
1907 
1908  images = mos_extract_objects(mappeds[j], NULL, skylocalmaps[j],
1909  origslits,
1910  ext_mode, ron, gain, 1);
1911 
1912  cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
1913 
1914  if (images) {
1915  if (time_normalise)
1916  cpl_image_divide_scalar(images[0], alltime);
1917 
1918  mos_rebin_signal(images, group);
1919 
1920  if (!j) {
1921  if(dfs_save_image_null(frameset, parlist,
1922  reduced_science_tag,
1923  recipe, version)) {
1924  fors_pmos_science_exit(NULL, nscience);
1925  }
1926  }
1927 
1928  if (dfs_save_image_ext(images[0], reduced_science_tag,
1929  header)) {
1930  fors_pmos_science_exit(NULL, nscience);
1931  }
1932 
1933  reduceds[j] = images[0];
1934 
1935  if (time_normalise)
1936  cpl_image_divide_scalar(images[1], alltime);
1937 
1938  mos_rebin_signal(images + 1, group);
1939 
1940  if (!j) {
1941  if(dfs_save_image_null(frameset, parlist,
1942  reduced_sky_tag,
1943  recipe, version)) {
1944  fors_pmos_science_exit(NULL, nscience);
1945  }
1946  }
1947 
1948  if (dfs_save_image_ext(images[1], reduced_sky_tag,
1949  header)) {
1950  fors_pmos_science_exit(NULL, nscience);
1951  }
1952  cpl_image_delete(images[1]);
1953 
1954  if (time_normalise)
1955  cpl_image_divide_scalar(images[2], alltime);
1956 
1957  mos_rebin_error(images + 2, group);
1958 
1959  if (!j) {
1960  if(dfs_save_image_null(frameset, parlist,
1961  reduced_error_tag,
1962  recipe, version)) {
1963  fors_pmos_science_exit(NULL, nscience);
1964  }
1965  }
1966 
1967  if (dfs_save_image_ext(images[2], reduced_error_tag,
1968  header)) {
1969  fors_pmos_science_exit(NULL, nscience);
1970  }
1971 
1972  rerrors[j] = images[2];
1973 
1974  cpl_free(images);
1975  }
1976  else {
1977  cpl_msg_warning(recipe, "No objects found: the products "
1978  "%s, %s, and %s are not created",
1979  reduced_science_tag, reduced_sky_tag,
1980  reduced_error_tag);
1981  }
1982 
1983  }
1984 
1985  if (skymedian || skylocal) {
1986  if (time_normalise)
1987  cpl_image_divide_scalar(mappeds[j], alltime);
1988 
1989  if (!j) {
1990  if(dfs_save_image_null(frameset, parlist,
1991  mapped_science_tag,
1992  recipe, version)) {
1993  fors_pmos_science_exit(NULL, nscience);
1994  }
1995  }
1996 
1997  if (dfs_save_image_ext(mappeds[j], mapped_science_tag,
1998  header)) {
1999  fors_pmos_science_exit(NULL, nscience);
2000  }
2001  }
2002 
2003  cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
2004  cpl_propertylist_delete(header); header = NULL;
2005 
2006  }
2007 
2008  cpl_table_delete(origslits);
2009 
2010  /* Stokes computation */
2011 
2012  nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
2013  nx = cpl_image_get_size_x(reduceds[0]);
2014 
2015  header = cpl_propertylist_new();
2016  cpl_propertylist_update_double(header, "CRPIX1", 1.0);
2017  cpl_propertylist_update_double(header, "CRPIX2", 1.0);
2018  cpl_propertylist_update_double(header, "CRVAL1",
2019  startwavelength + (dispersion * group)/2);
2020  cpl_propertylist_update_double(header, "CRVAL2", 1.0);
2021  cpl_propertylist_update_double(header, "CD1_1", dispersion * group);
2022  cpl_propertylist_update_double(header, "CD1_2", 0.0);
2023  cpl_propertylist_update_double(header, "CD2_1", 0.0);
2024  cpl_propertylist_update_double(header, "CD2_2", 1.0);
2025  cpl_propertylist_update_string(header, "CTYPE1", "LINEAR");
2026  cpl_propertylist_update_string(header, "CTYPE2", "PIXEL");
2027 
2028  if (circ) {
2029 
2030  cpl_image *pv_im = NULL;
2031  cpl_image *pi_im = NULL;
2032  cpl_image *pvnull_im = NULL;
2033  cpl_image *pierr_im = NULL;
2034  cpl_image *perr_im = NULL;
2035 
2036  double *p_v = NULL;
2037  double *p_i = NULL;
2038  double *p_vnull = NULL;
2039  double *perr = NULL;
2040  double *pierr = NULL;
2041 
2042  double mean_vnull;
2043 
2044  int p = -1;
2045  int total = 0;
2046 
2047  pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2048  perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2049  pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2050  pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2051 
2052  p_v = cpl_image_get_data_double(pv_im);
2053  perr = cpl_image_get_data_double(perr_im);
2054  p_i = cpl_image_get_data_double(pi_im);
2055  pierr = cpl_image_get_data_double(pierr_im);
2056 
2057  if (nscience / 2 > 1) {
2058  pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2059  p_vnull = cpl_image_get_data_double(pvnull_im);
2060  }
2061 
2062  for (j = 0; j < nobjects; j++) {
2063 
2064  FILE *file; // Bagoo
2065  char *filename; // Bagoo
2066 
2067  int m;
2068 
2069  double * ip_v, * ip_i, * ipierr,
2070  * ip_vnull, * iperr;
2071 
2072  float * data;
2073  float * iff, * ierr;
2074 
2075  ip_v = p_v + (nobjects - 1 - j) * nx;
2076 
2077  if (nscience / 2 > 1)
2078  ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
2079 
2080  iperr = perr + (nobjects - 1 - j) * nx;
2081 
2082  ip_i = p_i + (nobjects - 1 - j) * nx;
2083  ipierr = pierr + (nobjects - 1 - j) * nx;
2084 
2085  total = 0;
2086  for (i = 0; i < nslits; i += 2) {
2087  total += nobjs_per_slit[i];
2088  if (total > j) {
2089  p = i;
2090  break;
2091  }
2092  }
2093 
2094  for (int k = 0; k < nscience / 2; k++) {
2095  float *if_o, *if_e, *ifdelta_o, *ifdelta_e;
2096  float *if_o_err, *if_e_err, *ifdelta_o_err, *ifdelta_e_err;
2097 
2098  int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45);
2099  int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
2100 
2101 
2102  data = cpl_image_get_data_float(reduceds[pos]);
2103 
2104  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2105  + (total - j - 1)) * nx;
2106 
2107  if_e = data + (2 * (nobjects - total)
2108  + (total - j - 1)) * nx;
2109 
2110  data = cpl_image_get_data_float(reduceds[pos_d]);
2111 
2112  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2113  + (total - j - 1)) * nx;
2114 
2115  ifdelta_e = data + (2 * (nobjects - total)
2116  + (total - j - 1)) * nx;
2117 
2118  data = cpl_image_get_data_float(rerrors[pos]);
2119 
2120  if_o_err = data
2121  + (2 * (nobjects - total) + nobjs_per_slit[p]
2122  + (total - j - 1)) * nx;
2123 
2124  if_e_err = data + (2 * (nobjects - total)
2125  + (total - j - 1)) * nx;
2126 
2127  data = cpl_image_get_data_float(rerrors[pos_d]);
2128 
2129  ifdelta_o_err = data
2130  + (2 * (nobjects - total) + nobjs_per_slit[p]
2131  + (total - j - 1)) * nx;
2132 
2133  ifdelta_e_err = data + (2 * (nobjects - total)
2134  + (total - j - 1)) * nx;
2135 
2136  if (bagoo) {
2137 
2138  char *signal_to_noise = getenv("SIGNAL_TO_NOISE" );
2139  float s2n = 100.;
2140  char *min_s2n = getenv("MIN_S2N" );
2141  int ms2n = 50;
2142 
2143  if (signal_to_noise)
2144  s2n = atof(signal_to_noise);
2145 
2146  if (min_s2n)
2147  ms2n = atoi(min_s2n);
2148 
2149  /*
2150  * Check whether S/N is > s2n in more than ms2n pixels
2151  * (on first frame, on ordinary beam)
2152  */
2153 
2154  if (k == 0) {
2155  bright = 0;
2156  for (m = 0; m < nx; m++) {
2157  if (if_o_err[m] > 0.0) {
2158  if (if_o[m]/if_o_err[m] > s2n) {
2159  bright++;
2160  if (bright > ms2n) {
2161  break;
2162  }
2163  }
2164  }
2165  }
2166  }
2167 
2168  if (bright > ms2n) {
2169  conta++;
2170  filename = cpl_sprintf("angle_%d_%d.dat",
2171  180*k-45, conta);
2172  file = fopen(filename, "w");
2173 
2174  fprintf(file, "%d\n", p + 2);
2175 
2176  for (m = 0; m < nx; m++) {
2177  double lambda = startwavelength
2178  + dispersion * group * (0.5 + m);
2179  fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n",
2180  lambda, if_o[m], if_o_err[m],
2181  if_e[m], if_e_err[m]);
2182  }
2183 
2184  fclose(file);
2185  cpl_free(filename);
2186 
2187  filename = cpl_sprintf("angle_%d_%d.dat",
2188  180*k+45, conta);
2189  file = fopen(filename, "w");
2190 
2191  fprintf(file, "%d\n", p + 2);
2192 
2193  for (m = 0; m < nx; m++) {
2194  double lambda = startwavelength
2195  + dispersion * group * (0.5 + m);
2196  fprintf(file, "%.3f %.9e %.9e %.9e %.9e\n",
2197  lambda, ifdelta_o[m], ifdelta_o_err[m],
2198  ifdelta_e[m], ifdelta_e_err[m]);
2199  }
2200 
2201  fclose(file);
2202  cpl_free(filename);
2203  }
2204  else {
2205  cpl_msg_info(recipe,
2206  "Extracted signal not written to "
2207  "ASCII (S/N > %.0f only in %d < %d "
2208  "bins)", s2n, bright, ms2n);
2209  }
2210  } // End of bagoo
2211 
2212  for (m = 0; m < nx; m++) {
2213 
2214  double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
2215  (if_o[m] - if_e[m] ) /
2216  (if_o[m] + if_e[m] ) -
2217  (ifdelta_o[m] - ifdelta_e[m]) /
2218  (ifdelta_o[m] + ifdelta_e[m]);
2219 
2220  quantity = isfinite(quantity) ? quantity : 0.0;
2221 
2222  /* PQ map computation */
2223  ip_v[m] += quantity * 0.5 / (nscience / 2);
2224 
2225  /* PQnull map computation */
2226  if (nscience / 2 > 1) {
2227  if (k % 2)
2228  ip_vnull[m] += quantity * 0.5 / (nscience / 2);
2229  else
2230  ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
2231  }
2232 
2233  /* I map computation */
2234  ip_i[m] += (if_o[m] + if_e[m] +
2235  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2236 
2237  /* Variance map computation */
2238  ipierr[m] += (if_o_err[m] * if_o_err[m]
2239  + if_e_err[m] * if_e_err[m]
2240  + ifdelta_o_err[m] * ifdelta_o_err[m]
2241  + ifdelta_e_err[m] * ifdelta_e_err[m])
2242  / nscience / nscience;
2243 
2244  }
2245  }
2246 
2247  /* Error map */
2248  data = cpl_image_get_data_float(reduceds[0]);
2249  iff = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2250 
2251  data = cpl_image_get_data_float(rerrors[0]);
2252  ierr = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2253 
2254  for (m = 0; m < nx; m++)
2255  iperr[m] = iff[m] <= 0.0 ?
2256  0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
2257 
2258  if (nscience / 2 > 1) {
2259  float * weights;
2260  float max, sum, sum2, imean;
2261 
2262  int k;
2263 
2264  /* QC on U NULL */
2265  weights = cpl_malloc(sizeof(float) * nx);
2266 
2267  max = 0.0;
2268  for (k = 0; k < nx; k++) {
2269  if (max < iff[k]) max = iff[k];
2270  }
2271 
2272  for (k = 0; k < nx; k++) {
2273  weights[k] = iff[k] < 0.0 ?
2274  0.0 : iff[k] * iff[k] / (max * max);
2275  }
2276 
2277  sum = 0.0;
2278  sum2 = 0.0;
2279  for (k = 0; k < nx; k++) {
2280  sum += weights[k] * ip_vnull[k];
2281  sum2 += weights[k];
2282  }
2283 
2284  cpl_free(weights);
2285 
2286  imean = sum / sum2;
2287 
2288  mean_vnull += (imean - mean_vnull) / (j + 1.0);
2289  }
2290  }
2291 
2292  fors_dfs_save_image(frameset, pv_im, reduced_v_tag, header,
2293  parlist, recipe, ref_sci_frame);
2294  if(cpl_error_get_code() != CPL_ERROR_NONE)
2295  fors_pmos_science_exit(NULL, nscience);
2296 
2297  fors_dfs_save_image(frameset, pi_im, reduced_i_tag, header,
2298  parlist, recipe, ref_sci_frame);
2299  if(cpl_error_get_code() != CPL_ERROR_NONE)
2300  fors_pmos_science_exit(NULL, nscience);
2301 
2302  if (nscience / 2 > 1) {
2303  char *pipefile;
2304  char *keyname;
2305  cpl_propertylist *qheader;
2306 
2307  qheader = dfs_load_header(frameset, science_tag, 0);
2308  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
2309  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
2310  cpl_propertylist_update_double(qheader, "CRVAL1",
2311  startwavelength + (dispersion * group)/2);
2312  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
2313  cpl_propertylist_update_double(qheader, "CD1_1",
2314  dispersion * group);
2315  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
2316  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
2317  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
2318  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
2319  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
2320 
2321  if (qc) {
2322  fors_qc_start_group(qheader, "2.0", instrume);
2323 
2324  /*
2325  * QC1 group header
2326  */
2327 
2328  if (fors_qc_write_string("PRO.CATG", reduced_nul_v_tag,
2329  "Product category", instrume))
2330  fors_pmos_science_exit("Cannot write product category to "
2331  "QC log file", nscience);
2332 
2333  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
2334  "DPR type", instrume))
2335  fors_pmos_science_exit("Missing keyword DPR TYPE in "
2336  "scientific frame header", nscience);
2337 
2338  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
2339  "Template", instrume))
2340  fors_pmos_science_exit("Missing keyword TPL ID in "
2341  "scientific frame header", nscience);
2342 
2343  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
2344  "Grism name", instrume))
2345  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
2346  "scientific frame header", nscience);
2347 
2348  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
2349  "Grism identifier", instrume))
2350  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
2351  "scientific frame header", nscience);
2352 
2353  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
2354  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
2355  "Filter name", instrume);
2356 
2357  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
2358  "Collimator name", instrume))
2359  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
2360  "scientific frame header", nscience);
2361 
2362  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
2363  "Chip identifier", instrume))
2364  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
2365  "scientific frame header", nscience);
2366 
2367  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
2368  "Archive name of input data",
2369  instrume))
2370  fors_pmos_science_exit("Missing keyword ARCFILE in "
2371  "scientific frame header", nscience);
2372 
2373  pipefile = dfs_generate_filename(reduced_nul_v_tag);
2374  if (fors_qc_write_string("PIPEFILE", pipefile,
2375  "Pipeline product name", instrume))
2376  fors_pmos_science_exit("Cannot write PIPEFILE to "
2377  "QC log file", nscience);
2378  cpl_free(pipefile); pipefile = NULL;
2379 
2380 
2381  /*
2382  * QC1 parameters
2383  */
2384 
2385  keyname = "QC.NULL.V.MEAN";
2386 
2387  if (fors_qc_write_qc_double(qheader, mean_vnull,
2388  keyname, NULL,
2389  "Mean V null parameter",
2390  instrume)) {
2391  fors_pmos_science_exit("Cannot write mean Q null "
2392  "parameter to QC log file.", nscience);
2393  }
2394 
2395  keyname = "QC.NANGLES";
2396 
2397  if (fors_qc_write_qc_int(qheader, nscience,
2398  keyname, NULL,
2399  "Number of processed plate angles",
2400  instrume)) {
2401  fors_pmos_science_exit("Cannot write number of processed "
2402  "plate angles.", nscience);
2403  }
2404 
2406  }
2407 
2408  fors_dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader,
2409  parlist, recipe, ref_sci_frame);
2410  if(cpl_error_get_code() != CPL_ERROR_NONE)
2411  fors_pmos_science_exit(NULL, nscience);
2412 
2413  cpl_propertylist_delete(qheader);
2414  }
2415 
2416  fors_dfs_save_image(frameset, perr_im, reduced_error_v_tag, header,
2417  parlist, recipe, ref_sci_frame);
2418  if(cpl_error_get_code() != CPL_ERROR_NONE)
2419  fors_pmos_science_exit(NULL, nscience);
2420 
2421  cpl_image_power(pierr_im, 0.5);
2422 
2423  fors_dfs_save_image(frameset, pierr_im, reduced_error_i_tag, header,
2424  parlist, recipe, ref_sci_frame);
2425  if(cpl_error_get_code() != CPL_ERROR_NONE)
2426  fors_pmos_science_exit(NULL, nscience);
2427 
2428  cpl_image_delete(pv_im);
2429  cpl_image_delete(pvnull_im);
2430  cpl_image_delete(perr_im);
2431  cpl_image_delete(pi_im);
2432  cpl_image_delete(pierr_im);
2433  }
2434  else { /* Linear polarisation */
2435  cpl_image *pq_im = NULL;
2436  cpl_image *pu_im = NULL;
2437  cpl_image *pl_im = NULL;
2438  cpl_image *pi_im = NULL;
2439 
2440  cpl_image *pqnull_im = NULL;
2441  cpl_image *punull_im = NULL;
2442 
2443  cpl_image *pqerr_im = NULL;
2444  cpl_image *puerr_im = NULL;
2445  cpl_image *plerr_im = NULL;
2446  cpl_image *pierr_im = NULL;
2447 
2448  cpl_image *pang_im = NULL;
2449  cpl_image *pangerr_im = NULL;
2450 
2451  double *p_q = NULL;
2452  double *p_u = NULL;
2453  double *p_l = NULL;
2454  double *p_i = NULL;
2455 
2456  double *p_qnull = NULL;
2457  double *p_unull = NULL;
2458 
2459  double *pqerr = NULL;
2460  double *puerr = NULL;
2461  double *plerr = NULL;
2462  double *pierr = NULL;
2463 
2464  double *pang = NULL;
2465  double *pangerr = NULL;
2466 
2467  int m;
2468 
2469  cpl_image *correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
2470  double *correct = cpl_image_get_data_double(correct_im);
2471 
2472  double mean_unull, mean_qnull;
2473 
2474  int p = -1;
2475  int total = 0;
2476 
2477  pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2478  pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2479  pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2480  pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2481 
2482  pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2483  puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2484  plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2485  pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2486 
2487  pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2488  pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2489 
2490  p_q = cpl_image_get_data_double(pq_im);
2491  p_u = cpl_image_get_data_double(pu_im);
2492  p_l = cpl_image_get_data_double(pl_im);
2493  p_i = cpl_image_get_data_double(pi_im);
2494 
2495  if (nscience / 4 > 1) {
2496  pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2497  punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2498 
2499  p_qnull = cpl_image_get_data_double(pqnull_im);
2500  p_unull = cpl_image_get_data_double(punull_im);
2501  } else {
2502  cpl_msg_warning(cpl_func,
2503  "Not enough pairs to compute null parameters");
2504  }
2505 
2506  pqerr = cpl_image_get_data_double(pqerr_im);
2507  puerr = cpl_image_get_data_double(puerr_im);
2508  plerr = cpl_image_get_data_double(plerr_im);
2509  pierr = cpl_image_get_data_double(pierr_im);
2510 
2511  pang = cpl_image_get_data_double(pang_im);
2512  pangerr = cpl_image_get_data_double(pangerr_im);
2513 
2514  if (chromatism) {
2515  cpl_table * chrotbl =
2516  dfs_load_table(frameset, chrom_table_tag, 1);
2517 
2518  int nrow = cpl_table_get_nrow(chrotbl);
2519  float * lambda = cpl_table_get_data_float(chrotbl, "lambda");
2520  float * theta = cpl_table_get_data_float(chrotbl, "eps_theta");
2521 
2522  for (j = 0; j < nx; j++) {
2523  double c_wave = startwavelength
2524  + (dispersion * group) / 2
2525  + j * dispersion * group;
2526 
2527  int found = 0;
2528  int k;
2529 
2530  for (k = 0; k < nrow - 1; k++) {
2531  if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
2532  found = 1;
2533  break;
2534  }
2535  }
2536 
2537  if (found) {
2538  correct[j] = (theta [k + 1] - theta [k]) /
2539  (lambda[k + 1] - lambda[k]) *
2540  (c_wave - lambda[k]) + theta[k];
2541  correct[j] *= M_PI / 180; /* Radians */
2542  }
2543  else if (j)
2544  correct[j] = correct[j-1];
2545  else
2546  correct[j] = 0.0;
2547  }
2548 
2549  cpl_table_delete(chrotbl);
2550  }
2551 
2552  for (j = 0; j < nobjects; j++) {
2553  double *ip_q;
2554  double *ip_u;
2555  double *ip_l;
2556  double *ip_i;
2557  double *ipierr;
2558  double *ip_qnull;
2559  double *ip_unull;
2560  double *ipqerr;
2561  double *ipuerr;
2562  double *iplerr;
2563  double *ipang;
2564  double *ipangerr;
2565 
2566  float *data;
2567  float *iffq;
2568  float *ierrq;
2569  float *iffu;
2570  float *ierru;
2571 
2572  int pos, pos_d;
2573 
2574  ip_q = p_q + (nobjects - 1 - j) * nx;
2575  ip_u = p_u + (nobjects - 1 - j) * nx;
2576  ip_l = p_l + (nobjects - 1 - j) * nx;
2577  ip_i = p_i + (nobjects - 1 - j) * nx;
2578 
2579  if (nscience / 4 > 1) {
2580  ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
2581  ip_unull = p_unull + (nobjects - 1 - j) * nx;
2582  }
2583 
2584  ipqerr = pqerr + (nobjects - 1 - j) * nx;
2585  ipuerr = puerr + (nobjects - 1 - j) * nx;
2586  iplerr = plerr + (nobjects - 1 - j) * nx;
2587  ipierr = pierr + (nobjects - 1 - j) * nx;
2588 
2589  ipang = pang + (nobjects - 1 - j) * nx;
2590  ipangerr = pangerr + (nobjects - 1 - j) * nx;
2591 
2592  total = 0;
2593  for (i = 0; i < nslits; i += 2) {
2594  total += nobjs_per_slit[i];
2595  if (total > j) {
2596  p = i;
2597  break;
2598  }
2599  }
2600 
2601  for (int k = 0; k < nscience / 4; k++) {
2602  float * if_o, * if_e, * ifdelta_o, * ifdelta_e;
2603  float * if_o_err, * if_e_err, * ifdelta_o_err, * ifdelta_e_err;
2604 
2605  /* First P_Q */
2606 
2607  pos = fors_find_angle_pos(angles, nscience, 90 * k);
2608  pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
2609 
2610  data = cpl_image_get_data_float(reduceds[pos]);
2611 
2612  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2613  + (total - j - 1)) * nx;
2614 
2615  if_e = data + (2 * (nobjects - total)
2616  + (total - j - 1)) * nx;
2617 
2618  data = cpl_image_get_data_float(reduceds[pos_d]);
2619 
2620  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2621  + (total - j - 1)) * nx;
2622 
2623  ifdelta_e = data + (2 * (nobjects - total)
2624  + (total - j - 1)) * nx;
2625 
2626  data = cpl_image_get_data_float(rerrors[pos]);
2627 
2628  if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2629  + (total - j - 1)) * nx;
2630 
2631  if_e_err = data + (2 * (nobjects - total)
2632  + (total - j - 1)) * nx;
2633 
2634  data = cpl_image_get_data_float(rerrors[pos_d]);
2635 
2636  ifdelta_o_err = data + (2 * (nobjects - total)
2637  + nobjs_per_slit[p] + (total - j - 1)) * nx;
2638 
2639  ifdelta_e_err = data + (2 * (nobjects - total)
2640  + (total - j - 1)) * nx;
2641 
2642  for (m = 0; m < nx; m++) {
2643 
2644  double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2645  (if_o[m] - if_e[m] ) /
2646  (if_o[m] + if_e[m] ) -
2647  (ifdelta_o[m] - ifdelta_e[m]) /
2648  (ifdelta_o[m] + ifdelta_e[m]);
2649 
2650  quantity = isfinite(quantity) ? quantity : 0.0;
2651 
2652  /* PQ map computation */
2653  ip_q[m] += quantity * 0.5 / (nscience / 4);
2654 
2655  /* PQnull map computation */
2656  if (nscience / 4 > 1) {
2657  if (k % 2)
2658  ip_qnull[m] += quantity * 0.5 / (nscience / 4);
2659  else
2660  ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
2661  }
2662 
2663  /* I map computation */
2664  ip_i[m] += (if_o[m] + if_e[m] +
2665  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2666 
2667  /* Variance map computation */
2668  ipierr[m] += (if_o_err[m] * if_o_err[m]
2669  + if_e_err[m] * if_e_err[m]
2670  + ifdelta_o_err[m] * ifdelta_o_err[m]
2671  + ifdelta_e_err[m] * ifdelta_e_err[m])
2672  / nscience / nscience;
2673  }
2674 
2675  /* Now P_U */
2676 
2677  pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
2678  pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
2679 
2680  data = cpl_image_get_data_float(reduceds[pos]);
2681 
2682  if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2683  + (total - j - 1)) * nx;
2684 
2685  if_e = data + (2 * (nobjects - total)
2686  + (total - j - 1)) * nx;
2687 
2688  data = cpl_image_get_data_float(reduceds[pos_d]);
2689 
2690  ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2691  + (total - j - 1)) * nx;
2692 
2693  ifdelta_e = data + (2 * (nobjects - total)
2694  + (total - j - 1)) * nx;
2695 
2696  data = cpl_image_get_data_float(rerrors[pos]);
2697 
2698  if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2699  + (total - j - 1)) * nx;
2700 
2701  if_e_err = data + (2 * (nobjects - total)
2702  + (total - j - 1)) * nx;
2703 
2704  data = cpl_image_get_data_float(rerrors[pos_d]);
2705 
2706  ifdelta_o_err = data + (2 * (nobjects - total)
2707  + nobjs_per_slit[p] + (total - j - 1)) * nx;
2708 
2709  ifdelta_e_err = data + (2 * (nobjects - total)
2710  + (total - j - 1)) * nx;
2711 
2712  for (m = 0; m < nx; m++) {
2713 
2714  double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2715  (if_o[m] - if_e[m] ) /
2716  (if_o[m] + if_e[m] ) -
2717  (ifdelta_o[m] - ifdelta_e[m]) /
2718  (ifdelta_o[m] + ifdelta_e[m]);
2719 
2720  quantity = isfinite(quantity) ? quantity : 0.0;
2721 
2722  /* PU map computation */
2723  ip_u[m] += quantity * 0.5 / (nscience / 4);
2724 
2725  /* PUnull map computation */
2726  if (nscience / 4 > 1) {
2727  if (k % 2)
2728  ip_unull[m] += quantity * 0.5 / (nscience / 4);
2729  else
2730  ip_unull[m] -= quantity * 0.5 / (nscience / 4);
2731  }
2732 
2733  /* I map computation */
2734  ip_i[m] += (if_o[m] + if_e[m] +
2735  ifdelta_o[m] + ifdelta_e[m]) / nscience;
2736 
2737  /* Variance map computation */
2738  ipierr[m] += (if_o_err[m] * if_o_err[m]
2739  + if_e_err[m] * if_e_err[m]
2740  + ifdelta_o_err[m] * ifdelta_o_err[m]
2741  + ifdelta_e_err[m] * ifdelta_e_err[m])
2742  / nscience / nscience;
2743  }
2744  }
2745 
2746  /* Error map */
2747 
2748  pos = fors_find_angle_pos(angles, nscience, 0.0);
2749 
2750  data = cpl_image_get_data_float(reduceds[pos]);
2751  iffq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2752 
2753  data = cpl_image_get_data_float(rerrors[pos]);
2754  ierrq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2755 
2756  pos = fors_find_angle_pos(angles, nscience, 22.5);
2757 
2758  data = cpl_image_get_data_float(reduceds[pos]);
2759  iffu = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2760 
2761  data = cpl_image_get_data_float(rerrors[pos]);
2762  ierru = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2763 
2764  for (m = 0; m < nx; m++) {
2765 
2766  double radicand;
2767 
2768  ipqerr[m] = iffq[m] <= 0.0 ?
2769  0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
2770 
2771  ipuerr[m] = iffu[m] <= 0.0 ?
2772  0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
2773 
2774  iplerr[m] = 0.5 * (ipqerr[m] + ipuerr[m]);
2775 
2776  /* PL computation */
2777  ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
2778 
2779  /* P angle computation */
2780  if (fabs(ip_q[m]) < 0.00001) {
2781  if (ip_u[m] > 0.0) {
2782  ipang[m] = 45.0;
2783  }
2784  else {
2785  ipang[m] = 135.0;
2786  }
2787  }
2788  else {
2789  ipang[m] = 0.5 * atan(ip_u[m] / ip_q[m]) * 180 / M_PI;
2790  if (ip_q[m] > 0.0) {
2791  if (ip_u[m] < 0.0) {
2792  ipang[m] += 180.;
2793  }
2794  }
2795  else {
2796  ipang[m] += 90.;
2797  }
2798  }
2799 
2800  /* Error on the angle computation */
2801  radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] +
2802  ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
2803 
2804  ipangerr[m] = (ip_l[m] == 0.0 ? 0.0 :
2805  sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI);
2806 
2807  /*
2808  * This is a quick and dirty patch for FORS2 had the
2809  * Wolly mounted +180 with respect to FORS1. I must
2810  * hardcode it, because there is no such info in the
2811  * header.
2812  */
2813 
2814  if (instrume[4] == '2') {
2815 
2816  double w_rotation = - wollaston * M_PI / 2;
2817 
2818  ipang[m] -= w_rotation * 180 / M_PI;
2819 
2820  ip_q[m] = ip_q[m] * cos(2 * w_rotation)
2821  + ip_u[m] * sin(2 * w_rotation);
2822 
2823  ip_u[m] = ip_u[m] * cos(2 * w_rotation)
2824  - ip_q[m] * sin(2 * w_rotation);
2825  }
2826 
2827  if (chromatism) {
2828  ipang[m] -= correct[m] * 180 / M_PI;
2829 
2830  ip_q[m] = ip_q[m] * cos(2 * correct[m])
2831  + ip_u[m] * sin(2 * correct[m]);
2832 
2833  ip_u[m] = ip_u[m] * cos(2 * correct[m])
2834  - ip_q[m] * sin(2 * correct[m]);
2835  }
2836 
2837  if (ipang[m] < 0.0)
2838  ipang[m] += 180.;
2839  else if (ipang[m] >= 180.0)
2840  ipang[m] -= 180.;
2841  }
2842 
2843  if (nscience / 4 > 1) {
2844  float * weights;
2845  float max, sum, sum2, imean;
2846 
2847  int k;
2848 
2849  /* QC on Q NULL */
2850  weights = cpl_malloc(sizeof(float) * nx);
2851 
2852  max = 0.0;
2853  for (k = 0; k < nx; k++) {
2854  if (max < iffq[k]) max = iffq[k];
2855  }
2856 
2857  for (k = 0; k < nx; k++) {
2858  weights[k] = iffq[k] < 0.0 ?
2859  0.0 : iffq[k] * iffq[k] / (max * max);
2860  }
2861 
2862  sum = 0.0;
2863  sum2 = 0.0;
2864  for (k = 0; k < nx; k++) {
2865  sum += weights[k] * ip_qnull[k];
2866  sum2 += weights[k];
2867  }
2868 
2869  cpl_free(weights);
2870 
2871  imean = sum / sum2;
2872 
2873  mean_qnull += (imean - mean_qnull) / (j + 1.0);
2874 
2875  /* QC on U NULL */
2876  weights = cpl_malloc(sizeof(float) * nx);
2877 
2878  max = 0.0;
2879  for (k = 0; k < nx; k++) {
2880  if (max < iffu[k]) max = iffu[k];
2881  }
2882 
2883  for (k = 0; k < nx; k++) {
2884  weights[k] = iffu[k] < 0.0 ?
2885  0.0 : iffu[k] * iffu[k] / (max * max);
2886  }
2887 
2888  sum = 0.0;
2889  sum2 = 0.0;
2890  for (k = 0; k < nx; k++) {
2891  sum += weights[k] * ip_unull[k];
2892  sum2 += weights[k];
2893  }
2894 
2895  cpl_free(weights);
2896 
2897  imean = sum / sum2;
2898 
2899  mean_unull += (imean - mean_unull) / (j + 1.0);
2900  }
2901  }
2902 
2903  cpl_image_delete(correct_im);
2904 
2905  fors_dfs_save_image(frameset, pq_im, reduced_q_tag, header,
2906  parlist, recipe, ref_sci_frame);
2907  if(cpl_error_get_code() != CPL_ERROR_NONE)
2908  fors_pmos_science_exit(NULL, nscience);
2909 
2910  fors_dfs_save_image(frameset, pu_im, reduced_u_tag, header,
2911  parlist, recipe, ref_sci_frame);
2912  if(cpl_error_get_code() != CPL_ERROR_NONE)
2913  fors_pmos_science_exit(NULL, nscience);
2914 
2915  if (qc && standard) {
2916  cpl_table *polsta = dfs_load_table(frameset, std_pmos_table_tag, 1);
2917  cpl_propertylist *qheader = dfs_load_header(frameset,
2918  science_tag, 0);
2919  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
2920  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
2921  cpl_propertylist_update_double(qheader, "CRVAL1",
2922  startwavelength + (dispersion * group)/2);
2923  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
2924  cpl_propertylist_update_double(qheader, "CD1_1",
2925  dispersion * group);
2926  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
2927  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
2928  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
2929  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
2930  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
2931 
2932  if (mos_check_polarisation(pq_im, pqerr_im, pu_im, puerr_im,
2933  startwavelength, dispersion, 1000.,
2934  polsta, ra, dec, &filter,
2935  &polarised,
2936  &qc_pl, &qc_pl_err,
2937  &qc_angle, &qc_angle_err)) {
2938  cpl_msg_warning(cpl_func, "No QC can be computed");
2939  }
2940  else {
2941  char *pipefile;
2942  char *keyname;
2943  char *text;
2944  char band[] = {' ', '\0'};
2945 
2946  fors_qc_start_group(qheader, "2.0", instrume);
2947 
2948  /*
2949  * QC1 group header
2950  */
2951 
2952  if (fors_qc_write_string("PRO.CATG", reduced_l_tag,
2953  "Product category", instrume))
2954  fors_pmos_science_exit("Cannot write product category to "
2955  "QC log file", nscience);
2956 
2957  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
2958  "DPR type", instrume))
2959  fors_pmos_science_exit("Missing keyword DPR TYPE in "
2960  "scientific frame header", nscience);
2961 
2962  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
2963  "Template", instrume))
2964  fors_pmos_science_exit("Missing keyword TPL ID in "
2965  "scientific frame header", nscience);
2966 
2967  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
2968  "Grism name", instrume))
2969  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
2970  "scientific frame header", nscience);
2971 
2972  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
2973  "Grism identifier", instrume))
2974  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
2975  "scientific frame header", nscience);
2976 
2977  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
2978  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
2979  "Filter name", instrume);
2980 
2981  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
2982  "Collimator name", instrume))
2983  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
2984  "scientific frame header", nscience);
2985 
2986  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
2987  "Chip identifier", instrume))
2988  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
2989  "scientific frame header", nscience);
2990 
2991  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
2992  "Archive name of input data",
2993  instrume))
2994  fors_pmos_science_exit("Missing keyword ARCFILE in "
2995  "scientific frame header", nscience);
2996 
2997  pipefile = dfs_generate_filename(reduced_nul_q_tag);
2998  if (fors_qc_write_string("PIPEFILE", pipefile,
2999  "Pipeline product name", instrume))
3000  fors_pmos_science_exit("Cannot write PIPEFILE to "
3001  "QC log file", nscience);
3002  cpl_free(pipefile); pipefile = NULL;
3003 
3004 
3005  /*
3006  * QC1 parameters
3007  */
3008 
3009  keyname = "QC.PMOS.BAND";
3010 
3011  band[0] = filter;
3012  if (fors_qc_write_qc_string(qheader, keyname, band,
3013  "Band where polarisation was "
3014  "measured", instrume)) {
3015  fors_pmos_science_exit("Cannot write QC.PMOS.BAND "
3016  "parameter to QC log file", nscience);
3017  }
3018 
3019  keyname = "QC.PMOS.POLARISED";
3020 
3021  if (fors_qc_write_qc_int(qheader, polarised, keyname, NULL,
3022  "Polarisation is expected (1 = yes, "
3023  "0 = no)", instrume)) {
3024  fors_pmos_science_exit("Cannot write QC.PMOS.POLARISED "
3025  "parameter to QC log file", nscience);
3026  }
3027 
3028  keyname = "QC.PMOS.L.OFFSET";
3029 
3030  if (polarised)
3031  text = "Linear polarisation relative offset";
3032  else
3033  text = "Linear polarisation offset";
3034 
3035  if (fors_qc_write_qc_double(qheader, qc_pl, keyname, NULL,
3036  text, instrume)) {
3037  fors_pmos_science_exit("Cannot write linear polarisation "
3038  "offset to QC log file", nscience);
3039  }
3040 
3041  keyname = "QC.PMOS.L.OFFSETERR";
3042 
3043  if (fors_qc_write_qc_double(qheader, qc_pl_err, keyname, NULL,
3044  "Error on linear polarisation offset",
3045  instrume)) {
3046  fors_pmos_science_exit("Cannot write linear polarisation "
3047  "offset error to QC log file", nscience);
3048  }
3049 
3050  if (polarised) {
3051  keyname = "QC.PMOS.ANGLE.OFFSET";
3052 
3053  if (fors_qc_write_qc_double(qheader, qc_angle, keyname, NULL,
3054  "Polarisation angle offset",
3055  instrume)) {
3056  fors_pmos_science_exit("Cannot write polarisation "
3057  "angle offset to QC log file", nscience);
3058  }
3059 
3060  keyname = "QC.PMOS.ANGLE.OFFSETERR";
3061 
3062  if (fors_qc_write_qc_double(qheader, qc_angle_err, keyname,
3063  NULL, "Error on polarisation "
3064  "angle offset", instrume)) {
3065  fors_pmos_science_exit("Cannot write polarisation "
3066  "angle offset error to QC "
3067  "log file", nscience);
3068  }
3069  }
3070 
3072  }
3073 
3074  fors_dfs_save_image(frameset, pl_im, reduced_l_tag, qheader,
3075  parlist, recipe, ref_sci_frame);
3076  if(cpl_error_get_code() != CPL_ERROR_NONE)
3077  fors_pmos_science_exit(NULL, nscience);
3078 
3079  cpl_propertylist_delete(qheader);
3080  }
3081  else {
3082  fors_dfs_save_image(frameset, pl_im, reduced_l_tag, header,
3083  parlist, recipe, ref_sci_frame);
3084  if(cpl_error_get_code() != CPL_ERROR_NONE)
3085  fors_pmos_science_exit(NULL, nscience);
3086  }
3087 
3088  if (nscience / 4 > 1) {
3089  char *pipefile;
3090  char *keyname;
3091  cpl_propertylist *qheader = dfs_load_header(frameset,
3092  science_tag, 0);
3093 
3094  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
3095  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
3096  cpl_propertylist_update_double(qheader, "CRVAL1",
3097  startwavelength + (dispersion * group)/2);
3098  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
3099  cpl_propertylist_update_double(qheader, "CD1_1",
3100  dispersion * group);
3101  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
3102  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
3103  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
3104  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
3105  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
3106 
3107  if (qc) {
3108  fors_qc_start_group(qheader, "2.0", instrume);
3109 
3110  /*
3111  * QC1 group header
3112  */
3113 
3114  if (fors_qc_write_string("PRO.CATG", reduced_nul_q_tag,
3115  "Product category", instrume))
3116  fors_pmos_science_exit("Cannot write product category to "
3117  "QC log file", nscience);
3118 
3119  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
3120  "DPR type", instrume))
3121  fors_pmos_science_exit("Missing keyword DPR TYPE in "
3122  "scientific frame header", nscience);
3123 
3124  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
3125  "Template", instrume))
3126  fors_pmos_science_exit("Missing keyword TPL ID in "
3127  "scientific frame header", nscience);
3128 
3129  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
3130  "Grism name", instrume))
3131  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
3132  "scientific frame header", nscience);
3133 
3134  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
3135  "Grism identifier", instrume))
3136  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
3137  "scientific frame header", nscience);
3138 
3139  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
3140  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
3141  "Filter name", instrume);
3142 
3143  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
3144  "Collimator name", instrume))
3145  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
3146  "scientific frame header", nscience);
3147 
3148  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
3149  "Chip identifier", instrume))
3150  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
3151  "scientific frame header", nscience);
3152 
3153  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
3154  "Archive name of input data",
3155  instrume))
3156  fors_pmos_science_exit("Missing keyword ARCFILE in "
3157  "scientific frame header", nscience);
3158 
3159  pipefile = dfs_generate_filename(reduced_nul_q_tag);
3160  if (fors_qc_write_string("PIPEFILE", pipefile,
3161  "Pipeline product name", instrume))
3162  fors_pmos_science_exit("Cannot write PIPEFILE to "
3163  "QC log file", nscience);
3164  cpl_free(pipefile); pipefile = NULL;
3165 
3166 
3167  /*
3168  * QC1 parameters
3169  */
3170 
3171  keyname = "QC.NULL.Q.MEAN";
3172 
3173  if (fors_qc_write_qc_double(qheader, mean_qnull,
3174  keyname, NULL,
3175  "Mean Q null parameter",
3176  instrume)) {
3177  fors_pmos_science_exit("Cannot write mean Q null "
3178  "parameter to QC log file", nscience);
3179  }
3180 
3181  keyname = "QC.NANGLES";
3182 
3183  if (fors_qc_write_qc_int(qheader, nscience / 2,
3184  keyname, NULL,
3185  "Number of processed plate angles",
3186  instrume)) {
3187  fors_pmos_science_exit("Cannot write number of processed "
3188  "plate angles.", nscience);
3189  }
3190 
3192  }
3193 
3194  fors_dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader,
3195  parlist, recipe, ref_sci_frame);
3196  if(cpl_error_get_code() != CPL_ERROR_NONE)
3197  fors_pmos_science_exit(NULL, nscience);
3198 
3199  cpl_propertylist_delete(qheader);
3200 
3201  qheader = dfs_load_header(frameset, science_tag, 0);
3202 
3203  cpl_propertylist_update_double(qheader, "CRPIX1", 1.0);
3204  cpl_propertylist_update_double(qheader, "CRPIX2", 1.0);
3205  cpl_propertylist_update_double(qheader, "CRVAL1",
3206  startwavelength + (dispersion * group)/2);
3207  cpl_propertylist_update_double(qheader, "CRVAL2", 1.0);
3208  cpl_propertylist_update_double(qheader, "CD1_1",
3209  dispersion * group);
3210  cpl_propertylist_update_double(qheader, "CD1_2", 0.0);
3211  cpl_propertylist_update_double(qheader, "CD2_1", 0.0);
3212  cpl_propertylist_update_double(qheader, "CD2_2", 1.0);
3213  cpl_propertylist_update_string(qheader, "CTYPE1", "LINEAR");
3214  cpl_propertylist_update_string(qheader, "CTYPE2", "PIXEL");
3215 
3216  if (qc) {
3217  fors_qc_start_group(qheader, "2.0", instrume);
3218 
3219  /*
3220  * QC1 group header
3221  */
3222 
3223  if (fors_qc_write_string("PRO.CATG", reduced_nul_u_tag,
3224  "Product category", instrume))
3225  fors_pmos_science_exit("Cannot write product category to "
3226  "QC log file", nscience);
3227 
3228  if (fors_qc_keyword_to_paf(qheader, "ESO DPR TYPE", NULL,
3229  "DPR type", instrume))
3230  fors_pmos_science_exit("Missing keyword DPR TYPE in "
3231  "scientific frame header", nscience);
3232 
3233  if (fors_qc_keyword_to_paf(qheader, "ESO TPL ID", NULL,
3234  "Template", instrume))
3235  fors_pmos_science_exit("Missing keyword TPL ID in "
3236  "scientific frame header", nscience);
3237 
3238  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 NAME", NULL,
3239  "Grism name", instrume))
3240  fors_pmos_science_exit("Missing keyword INS GRIS1 NAME in "
3241  "scientific frame header", nscience);
3242 
3243  if (fors_qc_keyword_to_paf(qheader, "ESO INS GRIS1 ID", NULL,
3244  "Grism identifier", instrume))
3245  fors_pmos_science_exit("Missing keyword INS GRIS1 ID in "
3246  "scientific frame header", nscience);
3247 
3248  if (cpl_propertylist_has(qheader, "ESO INS FILT1 NAME"))
3249  fors_qc_keyword_to_paf(qheader, "ESO INS FILT1 NAME", NULL,
3250  "Filter name", instrume);
3251 
3252  if (fors_qc_keyword_to_paf(qheader, "ESO INS COLL NAME", NULL,
3253  "Collimator name", instrume))
3254  fors_pmos_science_exit("Missing keyword INS COLL NAME in "
3255  "scientific frame header", nscience);
3256 
3257  if (fors_qc_keyword_to_paf(qheader, "ESO DET CHIP1 ID", NULL,
3258  "Chip identifier", instrume))
3259  fors_pmos_science_exit("Missing keyword DET CHIP1 ID in "
3260  "scientific frame header", nscience);
3261 
3262  if (fors_qc_keyword_to_paf(qheader, "ARCFILE", NULL,
3263  "Archive name of input data",
3264  instrume))
3265  fors_pmos_science_exit("Missing keyword ARCFILE in "
3266  "scientific frame header", nscience);
3267 
3268  pipefile = dfs_generate_filename(reduced_nul_u_tag);
3269  if (fors_qc_write_string("PIPEFILE", pipefile,
3270  "Pipeline product name", instrume))
3271  fors_pmos_science_exit("Cannot write PIPEFILE to "
3272  "QC log file", nscience);
3273  cpl_free(pipefile); pipefile = NULL;
3274 
3275 
3276  /*
3277  * QC1 parameters
3278  */
3279 
3280  keyname = "QC.NULL.U.MEAN";
3281 
3282  if (fors_qc_write_qc_double(qheader, mean_unull,
3283  keyname, NULL,
3284  "Mean U null parameter",
3285  instrume)) {
3286  fors_pmos_science_exit("Cannot write mean U null "
3287  "parameter to QC log file", nscience);
3288  }
3289 
3290  keyname = "QC.NANGLES";
3291 
3292  if (fors_qc_write_qc_int(qheader, nscience / 2,
3293  keyname, NULL,
3294  "Number of processed plate angles",
3295  instrume)) {
3296  fors_pmos_science_exit("Cannot write number of processed "
3297  "plate angles.", nscience);
3298  }
3299 
3301  }
3302 
3303  fors_dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader,
3304  parlist, recipe, ref_sci_frame);
3305  if(cpl_error_get_code() != CPL_ERROR_NONE)
3306  fors_pmos_science_exit(NULL, nscience);
3307 
3308  cpl_propertylist_delete(qheader);
3309  }
3310 
3311  fors_dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header,
3312  parlist, recipe, ref_sci_frame);
3313  if(cpl_error_get_code() != CPL_ERROR_NONE)
3314  fors_pmos_science_exit(NULL, nscience);
3315 
3316  fors_dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header,
3317  parlist, recipe, ref_sci_frame);
3318  if(cpl_error_get_code() != CPL_ERROR_NONE)
3319  fors_pmos_science_exit(NULL, nscience);
3320 
3321  fors_dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header,
3322  parlist, recipe, ref_sci_frame);
3323  if(cpl_error_get_code() != CPL_ERROR_NONE)
3324  fors_pmos_science_exit(NULL, nscience);
3325 
3326  fors_dfs_save_image(frameset, pang_im, reduced_angle_tag, header,
3327  parlist, recipe, ref_sci_frame);
3328  if(cpl_error_get_code() != CPL_ERROR_NONE)
3329  fors_pmos_science_exit(NULL, nscience);
3330 
3331  fors_dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag,
3332  header, parlist, recipe, ref_sci_frame);
3333  if(cpl_error_get_code() != CPL_ERROR_NONE)
3334  fors_pmos_science_exit(NULL, nscience);
3335 
3336  fors_dfs_save_image(frameset, pi_im, reduced_i_tag,
3337  header, parlist, recipe, ref_sci_frame);
3338  if(cpl_error_get_code() != CPL_ERROR_NONE)
3339  fors_pmos_science_exit(NULL, nscience);
3340 
3341  cpl_image_power(pierr_im, 0.5);
3342 
3343  fors_dfs_save_image(frameset, pierr_im, reduced_error_i_tag,
3344  header, parlist, recipe, ref_sci_frame);
3345  if(cpl_error_get_code() != CPL_ERROR_NONE)
3346  fors_pmos_science_exit(NULL, nscience);
3347 
3348 /* %%% */
3349 
3350  cpl_image_delete(pq_im);
3351  cpl_image_delete(pu_im);
3352  cpl_image_delete(pl_im);
3353  cpl_image_delete(pi_im);
3354 
3355  cpl_image_delete(pqnull_im);
3356  cpl_image_delete(punull_im);
3357 
3358  cpl_image_delete(pqerr_im);
3359  cpl_image_delete(puerr_im);
3360  cpl_image_delete(plerr_im);
3361  cpl_image_delete(pierr_im);
3362  cpl_image_delete(pang_im);
3363  cpl_image_delete(pangerr_im);
3364  }
3365 
3366  cpl_propertylist_delete(header);
3367 
3368  /* End of Stokes computation */
3369 
3370  for (j = 0; j < nscience; j++) {
3371  cpl_image_delete(reduceds[j]);
3372  cpl_image_delete(rerrors[j]);
3373  cpl_table_delete(slitss[j]);
3374  cpl_image_delete(mappeds[j]);
3375  }
3376 
3377  cpl_free(reduceds);
3378  cpl_free(rerrors);
3379  cpl_free(slitss);
3380  cpl_free(mappeds);
3381 
3382  cpl_free(instrume); instrume = NULL;
3383 
3384  cpl_free(skylocalmaps);
3385 
3386  cpl_free(nobjs_per_slit);
3387 
3388  if (cpl_error_get_code()) {
3389  cpl_msg_error(cpl_error_get_where(), "%s", cpl_error_get_message());
3390  fors_pmos_science_exit(NULL, nscience);
3391  }
3392  else
3393  return 0;
3394 }
3395 
3396 /*----------------------------------------------------------------------------*/
3407 /*----------------------------------------------------------------------------*/
3408 static float * fors_check_angles(cpl_frameset * frameset,
3409  int pmos, const char *tag, int * circ)
3410 {
3411  float *angles = NULL;
3412  cpl_frame *c_frame = NULL;
3413  char *ret_id = NULL;
3414 
3415  int i = 0;
3416 
3417  angles = cpl_malloc(sizeof(float) * pmos);
3418 
3419  for (c_frame = cpl_frameset_find(frameset, tag);
3420  c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
3421 
3422  cpl_propertylist * header =
3423  cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
3424 
3425  if (!ret_id) {
3426  ret_id = cpl_strdup(cpl_propertylist_get_string(header,
3427  "ESO INS OPTI4 ID"));
3428 
3429  if (ret_id[1] != '5' && ret_id[1] != '4') {
3430  cpl_msg_error(cpl_func,
3431  "Unknown retarder plate id: %s", ret_id);
3432  return NULL;
3433  }
3434  } else {
3435  char * c_ret_id = (char *)
3436  cpl_propertylist_get_string(header, "ESO INS OPTI4 ID");
3437  if (ret_id[1] != c_ret_id[1]) {
3438  cpl_msg_error(cpl_func, "Input frames are not from the same "
3439  "retarder plate");
3440  return NULL;
3441  }
3442  }
3443 
3444  if (ret_id[1] == '5') { /* Linear polarimetry */
3445  if (cpl_propertylist_has(header, "ESO INS RETA2 ROT")) {
3446  angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3447  "ESO INS RETA2 ROT") + 0.5)/2;
3448  }
3449  else if (cpl_propertylist_has(header, "ESO INS RETA2 POSANG")) {
3450  if (cpl_propertylist_has(header, "ESO ADA POSANG")) {
3451  double reta2pos = cpl_propertylist_get_double(header,
3452  "ESO INS RETA2 POSANG");
3453  double adapos = cpl_propertylist_get_double(header,
3454  "ESO ADA POSANG");
3455  angles[i] = (float)floor(2*(reta2pos - adapos) + 0.5)/2;
3456  }
3457  else {
3458  cpl_msg_error(cpl_func,
3459  "ESO ADA POSANG not found in header");
3460  return NULL;
3461  }
3462  }
3463  else {
3464  cpl_msg_error(cpl_func, "Neither ESO INS RETA2 ROT nor "
3465  "ESO INS RETA2 POSANG found in header");
3466  return NULL;
3467  }
3468  *circ = 0;
3469  } else { /* Circular polarimetry */
3470  if (cpl_propertylist_has(header, "ESO INS RETA4 ROT")) {
3471  angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3472  "ESO INS RETA4 ROT") + 0.5)/2;
3473  //Check if it makes sense. Change in all other places
3474  if (angles[i] < 0)
3475  angles[i] = angles[i] + 360;
3476  }
3477  else if (cpl_propertylist_has(header, "ESO INS RETA4 POSANG")) {
3478  if (cpl_propertylist_has(header, "ESO ADA POSANG")) {
3479  double reta4pos = cpl_propertylist_get_double(header,
3480  "ESO INS RETA4 POSANG");
3481  double adapos = cpl_propertylist_get_double(header,
3482  "ESO ADA POSANG");
3483  angles[i] = (float)floor(2*(reta4pos - adapos) + 0.5/2);
3484  }
3485  else {
3486  cpl_msg_error(cpl_func,
3487  "ESO ADA POSANG not found in header");
3488  return NULL;
3489  }
3490  }
3491  else {
3492  cpl_msg_error(cpl_func, "Neither ESO INS RETA4 ROT nor "
3493  "ESO INS RETA4 POSANG found in header");
3494  return NULL;
3495  }
3496  *circ = 1;
3497  }
3498 
3499  cpl_propertylist_delete(header);
3500  i++;
3501  }
3502 
3503  cpl_free(ret_id);
3504 
3505  if (*circ) {
3506  if (pmos != 2 && pmos != 4) {
3507  cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
3508  "found, but either 2 or 4 are required for "
3509  "circular polarization measurements!", pmos);
3510  return NULL;
3511  }
3512  } else {
3513  if (pmos != 4 && pmos != 8 && pmos != 16) {
3514  cpl_msg_error(cpl_func, "Wrong angle configuration: %d angles "
3515  "found, but either 4, 8, or 16 are required for "
3516  "linear polarization measurements!", pmos);
3517  return NULL;
3518  }
3519  }
3520 
3521  /* Check completeness */
3522 
3523  if (*circ) {
3524  for (i = 0; i < pmos; i++) {
3525  if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
3526  const char *cangles;
3527  switch (pmos) {
3528  case 2: cangles = "-45.0, 45.0"; break;
3529  case 4: cangles = "-45.0, 45.0, 135.0, 225.0"; break;
3530  default: assert(0);
3531  }
3532 
3533  cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
3534  "angle %.2f. All angles %s must be provided.",
3535  angles[i], cangles);
3536  return NULL;
3537  }
3538  }
3539  }
3540  else {
3541  for (i = 0; i < pmos; i++) {
3542  if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
3543  const char *cangles;
3544  switch (pmos) {
3545  case 4: cangles = "0.0, 22.5, 45.0, 67.5"; break;
3546  case 8: cangles = "0.0, 22.5, 45.0, 67.5, "
3547  "90.0, 112.5, 135.0, 157.5"; break;
3548  case 16: cangles = "0.0, 22.5, 45.0, 67.5, "
3549  "90.0, 112.5, 135.0, 157.5, "
3550  "180.0, 202.5, 225.0, 247.5, "
3551  "270.0, 292.5, 315.0, 337.5"; break;
3552  default: assert(0);
3553  }
3554 
3555  cpl_msg_error(cpl_func, "Wrong angle configuration: missing "
3556  "angle %.2f. All angles %s must be provided.",
3557  angles[i], cangles);
3558  return NULL;
3559  }
3560  }
3561  }
3562 
3563  return angles;
3564 }
3565 
3566 /*----------------------------------------------------------------------------*/
3574 /*----------------------------------------------------------------------------*/
3575 static int
3576 fors_find_angle_pos(float * angles, int nangles, float angle)
3577 {
3578  int i, match = 0;
3579 
3580  for (i = 0; i < nangles; i++) {
3581  if (fabs(angles[i] - angle) < 1.0 ||
3582  fabs(angles[i] - 360.0 - angle) < 1.0) {
3583  match = 1;
3584  break;
3585  }
3586  }
3587 
3588  return match ? i : -1;
3589 }
3590 
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:8531
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:11068
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:11401
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:9718
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:15134
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:10007
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:13965
cpl_image * mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
Local determination of sky.
Definition: moses.c:12738
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:18396
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:16449
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:11290
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:14316
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:13195
cpl_error_code mos_randomise_image(cpl_image *image, double ron, double gain, double bias)
Randomise image.
Definition: moses.c:16215
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