40 #include <fors_utils.h>
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 *);
48 static float * fors_check_angles(cpl_frameset *,
int,
const char *,
int *);
50 fors_find_angle_pos(
float * angles,
int nangles,
float angle);
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"
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"
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"
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"
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";
112 #define fors_pmos_science_exit(message, nscience) \
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]); \
119 if(rerrors != NULL) { \
120 for (j = 0; j < nscience; j++) \
121 cpl_image_delete(rerrors[j]); \
123 if(slitss != NULL) { \
124 for (j = 0; j < nscience; j++) \
125 cpl_table_delete(slitss[j]); \
127 if(mappeds != NULL) { \
128 for (j = 0; j < nscience; j++) \
129 cpl_image_delete(mappeds[j]); \
131 if(skylocalmaps != NULL) { \
132 for (j = 0; j < nscience; j++) \
133 cpl_image_delete(skylocalmaps[j]); \
135 cpl_free(reduceds); \
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(); \
172 #define fors_pmos_science_exit_memcheck(message) \
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(); \
220 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
221 cpl_plugin *plugin = &recipe->interface;
223 cpl_plugin_init(plugin,
226 CPL_PLUGIN_TYPE_RECIPE,
228 "Extraction of scientific spectra",
229 fors_pmos_science_description,
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);
249 cpl_pluginlist_append(list, plugin);
265 static int fors_pmos_science_create(cpl_plugin *plugin)
275 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
276 recipe = (cpl_recipe *)plugin;
284 recipe->parameters = cpl_parameterlist_new();
291 p = cpl_parameter_new_value(
"fors.fors_pmos_science.dispersion",
293 "Expected spectral dispersion (Angstrom/pixel)",
294 "fors.fors_pmos_science",
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);
304 p = cpl_parameter_new_value(
"fors.fors_pmos_science.rebin",
307 "fors.fors_pmos_science",
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);
317 p = cpl_parameter_new_value(
"fors.fors_pmos_science.skyalign",
319 "Polynomial order for sky lines alignment, "
320 "or -1 to avoid alignment",
321 "fors.fors_pmos_science",
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);
331 p = cpl_parameter_new_value(
"fors.fors_pmos_science.wcolumn",
333 "Name of sky line catalog table column "
335 "fors.fors_pmos_science",
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);
345 p = cpl_parameter_new_value(
"fors.fors_pmos_science.startwavelength",
347 "Start wavelength in spectral extraction",
348 "fors.fors_pmos_science",
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);
358 p = cpl_parameter_new_value(
"fors.fors_pmos_science.endwavelength",
360 "End wavelength in spectral extraction",
361 "fors.fors_pmos_science",
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);
371 p = cpl_parameter_new_value(
"fors.fors_pmos_science.flux",
373 "Apply flux conservation",
374 "fors.fors_pmos_science",
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);
384 p = cpl_parameter_new_value(
"fors.fors_pmos_science.flatfield",
387 "fors.fors_pmos_science",
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);
397 p = cpl_parameter_new_value(
"fors.fors_pmos_science.skymedian",
399 "Sky subtraction from extracted slit spectra",
400 "fors.fors_pmos_science",
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);
410 p = cpl_parameter_new_value(
"fors.fors_pmos_science.skylocal",
412 "Sky subtraction from CCD slit spectra",
413 "fors.fors_pmos_science",
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);
423 p = cpl_parameter_new_value(
"fors.fors_pmos_science.cosmics",
425 "Eliminate cosmic rays hits (only if local "
426 "sky subtraction is also requested)",
427 "fors.fors_pmos_science",
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);
437 p = cpl_parameter_new_value(
"fors.fors_pmos_science.slit_margin",
439 "Number of pixels to exclude at each slit "
440 "in object detection and extraction",
441 "fors.fors_pmos_science",
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);
451 p = cpl_parameter_new_value(
"fors.fors_pmos_science.ext_radius",
453 "Maximum extraction radius for detected "
455 "fors.fors_pmos_science",
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);
465 p = cpl_parameter_new_value(
"fors.fors_pmos_science.cont_radius",
467 "Minimum distance at which two objects "
468 "of equal luminosity do not contaminate "
469 "each other (pixel)",
470 "fors.fors_pmos_science",
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);
480 p = cpl_parameter_new_value(
"fors.fors_pmos_science.ext_mode",
482 "Object extraction method: 0 = aperture, "
483 "1 = Horne optimal extraction",
484 "fors.fors_pmos_science",
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);
494 p = cpl_parameter_new_value(
"fors.fors_pmos_science.match_tolerance",
496 "Tolerance for matching spectra from the "
497 "same object at different angles and beams "
499 "fors.fors_pmos_science",
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);
509 p = cpl_parameter_new_value(
"fors.fors_pmos_science.time_normalise",
511 "Normalise output spectra by the exposure time",
512 "fors.fors_pmos_science",
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);
522 p = cpl_parameter_new_value(
"fors.fors_pmos_science.chromatism",
524 "Chromatism correction to polarization angles",
525 "fors.fors_pmos_science",
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);
535 p = cpl_parameter_new_value(
"fors.fors_pmos_science.wollaston",
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 "
541 "fors.fors_pmos_science",
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);
551 p = cpl_parameter_new_value(
"fors.fors_pmos_science.check",
553 "Create intermediate products",
554 "fors.fors_pmos_science",
556 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"check");
557 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
558 cpl_parameterlist_append(recipe->parameters, p);
564 p = cpl_parameter_new_value(
"fors.fors_pmos_science.qc",
566 "Compute QC1 parameters",
567 "fors.fors_pmos_science",
569 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"qc");
570 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
571 cpl_parameterlist_append(recipe->parameters, p);
585 static int fors_pmos_science_exec(cpl_plugin *plugin)
589 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
590 recipe = (cpl_recipe *)plugin;
594 return fors_pmos_science(recipe->parameters, recipe->frames);
606 static int fors_pmos_science_destroy(cpl_plugin *plugin)
610 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
611 recipe = (cpl_recipe *)plugin;
615 cpl_parameterlist_delete(recipe->parameters);
630 static int fors_pmos_science(cpl_parameterlist *parlist, cpl_frameset *frameset)
633 const char *recipe =
"fors_pmos_science";
644 double startwavelength;
645 double endwavelength;
668 cpl_image **reduceds = NULL;
669 cpl_image **rerrors = NULL;
670 cpl_table **slitss = NULL;
671 cpl_image **mappeds = NULL;
672 cpl_image **skylocalmaps = NULL;
676 cpl_image *bias = NULL;
677 cpl_image *norm_flat = NULL;
678 cpl_image *spectra = NULL;
679 cpl_image *rectified = NULL;
680 cpl_image *coordinate = NULL;
681 cpl_image *rainbow = NULL;
682 cpl_image *mapped = NULL;
683 cpl_image *mapped_sky = NULL;
684 cpl_image *mapped_cleaned = NULL;
685 cpl_image *smapped = NULL;
686 cpl_image *wavemap = NULL;
687 cpl_image *skymap = NULL;
688 cpl_image *skylocalmap = NULL;
689 cpl_image *dummy = NULL;
691 cpl_table *grism_table = NULL;
692 cpl_table *overscans = NULL;
693 cpl_table *wavelengths = NULL;
694 cpl_table *idscoeff = NULL;
695 cpl_table *slits = NULL;
696 cpl_table *origslits = NULL;
697 cpl_table *maskslits = NULL;
698 cpl_table *mask_science = NULL;
699 cpl_table *mask_arc = NULL;
700 cpl_table *mask_flat = NULL;
701 cpl_table *polytraces = NULL;
702 cpl_table *offsets = NULL;
703 cpl_table *sky = NULL;
705 cpl_vector *lines = NULL;
707 cpl_propertylist *header = NULL;
708 cpl_propertylist *save_header = NULL;
715 char *instrume = NULL;
716 const char *science_tag;
717 const char *master_norm_flat_tag;
718 const char *disp_coeff_tag;
719 const char *disp_coeff_sky_tag;
720 const char *wavelength_map_sky_tag;
721 const char *curv_coeff_tag;
722 const char *slit_location_tag;
723 const char *reduced_science_tag;
724 const char *reduced_sky_tag;
725 const char *reduced_error_tag;
726 const char *mapped_science_tag;
727 const char *unmapped_science_tag;
728 const char *mapped_science_sky_tag;
729 const char *mapped_sky_tag;
730 const char *unmapped_sky_tag;
731 const char *object_table_tag;
732 const char *object_table_pol_tag;
733 const char *skylines_offsets_tag;
734 const char *reduced_q_tag;
735 const char *reduced_u_tag;
736 const char *reduced_v_tag;
737 const char *reduced_l_tag;
738 const char *reduced_i_tag;
739 const char *reduced_error_q_tag;
740 const char *reduced_error_u_tag;
741 const char *reduced_error_v_tag;
742 const char *reduced_error_l_tag;
743 const char *reduced_error_i_tag;
744 const char *reduced_nul_q_tag;
745 const char *reduced_nul_u_tag;
746 const char *reduced_nul_v_tag;
747 const char *reduced_angle_tag;
748 const char *reduced_error_angle_tag;
749 const char *chrom_table_tag =
"RETARDER_WAVEPLATE_CHROMATISM";
750 const char *std_pmos_table_tag =
"STD_PMOS_TABLE";
751 float *angles = NULL;
760 int ccd_xsize, ccd_ysize;
783 int nslits_out_det = 0;
786 cpl_error_code error;
788 snprintf(version, 80,
"%s-%s", PACKAGE, PACKAGE_VERSION);
791 char *montecarlo = getenv(
"MONTECARLO");
794 doit = atoi(montecarlo);
798 cpl_msg_set_indentation(2);
807 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
808 cpl_msg_indent_more();
810 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
811 fors_pmos_science_exit(
"Too many in input: GRISM_TABLE", nscience);
816 "fors.fors_pmos_science.dispersion", grism_table);
818 if (dispersion <= 0.0)
819 fors_pmos_science_exit(
"Invalid spectral dispersion", nscience);
822 "fors.fors_pmos_science.rebin", NULL);
825 fors_pmos_science_exit(
"Invalid rebin factor", nscience);
828 "fors.fors_pmos_science.skyalign", NULL);
831 fors_pmos_science_exit(
"Max polynomial degree for sky alignment is 2", nscience);
834 "fors.fors_pmos_science.wcolumn", NULL);
837 "fors.fors_pmos_science.startwavelength", grism_table);
838 if (startwavelength < 3000.0 || startwavelength > 13000.0)
839 fors_pmos_science_exit(
"Invalid wavelength", nscience);
842 "fors.fors_pmos_science.endwavelength", grism_table);
843 if (endwavelength < 3000.0 || endwavelength > 13000.0)
844 fors_pmos_science_exit(
"Invalid wavelength", nscience);
846 if (endwavelength - startwavelength <= 0.0)
847 fors_pmos_science_exit(
"Invalid wavelength interval", nscience);
852 "fors.fors_pmos_science.flatfield",
856 "fors.fors_pmos_science.skylocal",
859 "fors.fors_pmos_science.skymedian",
863 "fors.fors_pmos_science.chromatism",
867 "fors.fors_pmos_science.wollaston",
870 wollaston = wollaston ? 0 : 1;
872 if (skylocal && skymedian)
873 fors_pmos_science_exit(
"Cannot apply sky subtraction both on "
874 "extracted and non-extracted spectra", nscience);
877 "fors.fors_pmos_science.cosmics", NULL);
881 fors_pmos_science_exit(
"Cosmic rays correction requires "
882 "skylocal=true", nscience);
885 "fors.fors_pmos_science.slit_margin",
888 fors_pmos_science_exit(
"Value must be zero or positive", nscience);
891 "fors.fors_pmos_science.ext_radius",
894 fors_pmos_science_exit(
"Value must be zero or positive", nscience);
897 "fors.fors_pmos_science.cont_radius",
900 fors_pmos_science_exit(
"Value must be zero or positive", nscience);
904 if (ext_mode < 0 || ext_mode > 1)
905 fors_pmos_science_exit(
"Invalid object extraction mode", nscience);
908 "fors.fors_pmos_science.match_tolerance", NULL);
909 if (tolerance <= 0.0)
910 fors_pmos_science_exit(
"Invalid object match tolerance", nscience);
913 "fors.fors_pmos_science.time_normalise", NULL);
916 "fors.fors_pmos_science.check", NULL);
920 cpl_table_delete(grism_table); grism_table = NULL;
922 if (cpl_error_get_code())
923 fors_pmos_science_exit(
"Failure getting the configuration parameters",nscience);
930 cpl_msg_indent_less();
931 cpl_msg_info(recipe,
"Check input set-of-frames:");
932 cpl_msg_indent_more();
935 cpl_frameset *subframeset = cpl_frameset_duplicate(frameset);
936 cpl_frameset_erase(subframeset,
"MASTER_BIAS");
939 cpl_msg_warning(cpl_func,
"Input frames are not from the same grism");
942 cpl_msg_warning(cpl_func,
"Input frames are not from the same filter");
945 cpl_msg_warning(cpl_func,
"Input frames are not from the same chip");
947 cpl_frameset_delete(subframeset);
951 pmos = cpl_frameset_count_tags(frameset,
"SCIENCE_PMOS");
954 pmos = cpl_frameset_count_tags(frameset,
"STANDARD_PMOS");
959 fors_pmos_science_exit(
"Missing input scientific frame", nscience);
961 angles = fors_check_angles(frameset, pmos,
962 standard ?
"STANDARD_PMOS" :
"SCIENCE_PMOS",
965 fors_pmos_science_exit(
"Polarization angles could not be read", nscience);
974 reduceds = (cpl_image **)cpl_malloc(
sizeof(cpl_image *) * nscience);
975 rerrors = (cpl_image **)cpl_malloc(
sizeof(cpl_image *) * nscience);
976 slitss = (cpl_table **)cpl_malloc(
sizeof(cpl_table *) * nscience);
977 mappeds = (cpl_image **)cpl_malloc(
sizeof(cpl_image *) * nscience);
978 skylocalmaps = (cpl_image **)cpl_malloc(
sizeof(cpl_image *) * nscience);
981 cpl_msg_info(recipe,
"PMOS data found");
983 science_tag =
"STANDARD_PMOS";
984 reduced_science_tag =
"REDUCED_STD_PMOS";
985 unmapped_science_tag =
"UNMAPPED_STD_PMOS";
986 mapped_science_tag =
"MAPPED_STD_PMOS";
987 mapped_science_sky_tag =
"MAPPED_ALL_STD_PMOS";
988 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_STD_PMOS";
989 wavelength_map_sky_tag =
"WAVELENGTH_MAP_STD_PMOS";
990 disp_coeff_sky_tag =
"DISP_COEFF_STD_PMOS";
991 mapped_sky_tag =
"MAPPED_SKY_STD_PMOS";
992 unmapped_sky_tag =
"UNMAPPED_SKY_STD_PMOS";
993 object_table_tag =
"OBJECT_TABLE_STD_PMOS";
994 object_table_pol_tag =
"OBJECT_TABLE_POL_STD_PMOS";
995 reduced_sky_tag =
"REDUCED_SKY_STD_PMOS";
996 reduced_error_tag =
"REDUCED_ERROR_STD_PMOS";
997 reduced_q_tag =
"REDUCED_Q_STD_PMOS";
998 reduced_u_tag =
"REDUCED_U_STD_PMOS";
999 reduced_v_tag =
"REDUCED_V_STD_PMOS";
1000 reduced_l_tag =
"REDUCED_L_STD_PMOS";
1001 reduced_i_tag =
"REDUCED_I_STD_PMOS";
1002 reduced_error_q_tag =
"REDUCED_ERROR_Q_STD_PMOS";
1003 reduced_error_u_tag =
"REDUCED_ERROR_U_STD_PMOS";
1004 reduced_error_v_tag =
"REDUCED_ERROR_V_STD_PMOS";
1005 reduced_error_l_tag =
"REDUCED_ERROR_L_STD_PMOS";
1006 reduced_error_i_tag =
"REDUCED_ERROR_I_STD_PMOS";
1007 reduced_nul_q_tag =
"REDUCED_NUL_Q_STD_PMOS";
1008 reduced_nul_u_tag =
"REDUCED_NUL_U_STD_PMOS";
1009 reduced_nul_v_tag =
"REDUCED_NUL_V_STD_PMOS";
1010 reduced_angle_tag =
"REDUCED_ANGLE_STD_PMOS";
1011 reduced_error_angle_tag =
"REDUCED_ERROR_ANGLE_STD_PMOS";
1014 science_tag =
"SCIENCE_PMOS";
1015 reduced_science_tag =
"REDUCED_SCI_PMOS";
1016 unmapped_science_tag =
"UNMAPPED_SCI_PMOS";
1017 mapped_science_tag =
"MAPPED_SCI_PMOS";
1018 mapped_science_sky_tag =
"MAPPED_ALL_SCI_PMOS";
1019 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_SCI_PMOS";
1020 wavelength_map_sky_tag =
"WAVELENGTH_MAP_SCI_PMOS";
1021 disp_coeff_sky_tag =
"DISP_COEFF_SCI_PMOS";
1022 mapped_sky_tag =
"MAPPED_SKY_SCI_PMOS";
1023 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_PMOS";
1024 object_table_tag =
"OBJECT_TABLE_SCI_PMOS";
1025 object_table_pol_tag =
"OBJECT_TABLE_POL_SCI_PMOS";
1026 reduced_sky_tag =
"REDUCED_SKY_SCI_PMOS";
1027 reduced_error_tag =
"REDUCED_ERROR_SCI_PMOS";
1028 reduced_q_tag =
"REDUCED_Q_SCI_PMOS";
1029 reduced_u_tag =
"REDUCED_U_SCI_PMOS";
1030 reduced_v_tag =
"REDUCED_V_SCI_PMOS";
1031 reduced_l_tag =
"REDUCED_L_SCI_PMOS";
1032 reduced_i_tag =
"REDUCED_I_SCI_PMOS";
1033 reduced_error_q_tag =
"REDUCED_ERROR_Q_SCI_PMOS";
1034 reduced_error_u_tag =
"REDUCED_ERROR_U_SCI_PMOS";
1035 reduced_error_v_tag =
"REDUCED_ERROR_V_SCI_PMOS";
1036 reduced_error_l_tag =
"REDUCED_ERROR_L_SCI_PMOS";
1037 reduced_error_i_tag =
"REDUCED_ERROR_I_SCI_PMOS";
1038 reduced_nul_q_tag =
"REDUCED_NUL_Q_SCI_PMOS";
1039 reduced_nul_u_tag =
"REDUCED_NUL_U_SCI_PMOS";
1040 reduced_nul_v_tag =
"REDUCED_NUL_V_SCI_PMOS";
1041 reduced_angle_tag =
"REDUCED_ANGLE_SCI_PMOS";
1042 reduced_error_angle_tag =
"REDUCED_ERROR_ANGLE_SCI_PMOS";
1045 master_norm_flat_tag =
"MASTER_NORM_FLAT_PMOS";
1046 disp_coeff_tag =
"DISP_COEFF_PMOS";
1047 curv_coeff_tag =
"CURV_COEFF_PMOS";
1048 slit_location_tag =
"SLIT_LOCATION_PMOS";
1050 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
1051 master_norm_flat_tag =
"MASTER_NORM_FLAT_LONG_PMOS";
1052 disp_coeff_tag =
"DISP_COEFF_LONG_PMOS";
1053 slit_location_tag =
"SLIT_LOCATION_LONG_PMOS";
1057 if (cpl_frameset_count_tags(frameset,
"MASTER_BIAS") == 0)
1058 fors_pmos_science_exit(
"Missing required input: MASTER_BIAS", nscience);
1060 if (cpl_frameset_count_tags(frameset,
"MASTER_BIAS") > 1)
1061 fors_pmos_science_exit(
"Too many in input: MASTER_BIAS", nscience);
1064 if (cpl_frameset_count_tags(frameset,
"MASTER_SKYLINECAT") > 1)
1065 fors_pmos_science_exit(
"Too many in input: MASTER_SKYLINECAT", nscience);
1067 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) == 0) {
1068 cpl_msg_error(recipe,
"Missing required input: %s", disp_coeff_tag);
1069 fors_pmos_science_exit(NULL, nscience);
1072 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) > 1) {
1073 cpl_msg_error(recipe,
"Too many in input: %s", disp_coeff_tag);
1074 fors_pmos_science_exit(NULL, nscience);
1077 if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
1078 cpl_msg_error(recipe,
"Missing required input: %s",
1080 fors_pmos_science_exit(NULL, nscience);
1083 if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
1084 cpl_msg_error(recipe,
"Too many in input: %s", slit_location_tag);
1085 fors_pmos_science_exit(NULL, nscience);
1089 if (cpl_frameset_count_tags(frameset, chrom_table_tag) == 0) {
1090 cpl_msg_error(recipe,
"Missing required input: %s",
1092 fors_pmos_science_exit(NULL, nscience);
1095 if (cpl_frameset_count_tags(frameset, chrom_table_tag) > 1) {
1096 cpl_msg_error(recipe,
"Too many in input: %s", chrom_table_tag);
1097 fors_pmos_science_exit(NULL, nscience);
1101 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
1103 cpl_msg_error(recipe,
"Too many in input: %s",
1104 master_norm_flat_tag);
1105 fors_pmos_science_exit(NULL, nscience);
1108 cpl_msg_warning(recipe,
"%s in input are ignored, "
1109 "since flat field correction was not requested",
1110 master_norm_flat_tag);
1114 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
1116 cpl_msg_warning(recipe,
"%s in input is ignored, "
1117 "since flat field correction was not requested",
1118 master_norm_flat_tag);
1122 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
1124 cpl_msg_error(recipe,
"Flat field correction was requested, "
1125 "but no %s are found in input",
1126 master_norm_flat_tag);
1127 fors_pmos_science_exit(NULL, nscience);
1132 if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) > 1) {
1133 cpl_msg_error(recipe,
"Too many in input: %s", std_pmos_table_tag);
1134 fors_pmos_science_exit(NULL, nscience);
1138 if (cpl_frameset_count_tags(frameset, std_pmos_table_tag) == 0) {
1139 cpl_msg_error(recipe,
"QC computation was requested, but no "
1140 "%s is found in input", std_pmos_table_tag);
1141 fors_pmos_science_exit(NULL, nscience);
1146 cpl_msg_indent_less();
1157 fors_pmos_science_exit(
"Cannot load scientific frame header", nscience);
1159 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
1160 if (instrume == NULL)
1161 fors_pmos_science_exit(
"Missing keyword INSTRUME in scientific header", nscience);
1162 instrume = cpl_strdup(instrume);
1164 if (instrume[4] ==
'1')
1165 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
1166 if (instrume[4] ==
'2')
1167 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
1169 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
1171 if (cpl_error_get_code() != CPL_ERROR_NONE)
1172 fors_pmos_science_exit(
"Missing keyword ESO INS GRIS1 WLEN in scientific "
1173 "frame header", nscience);
1175 if (reference < 3000.0)
1178 if (reference < 3000.0 || reference > 13000.0) {
1179 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
1180 "keyword ESO INS GRIS1 WLEN in scientific frame header",
1182 fors_pmos_science_exit(NULL, nscience);
1185 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
1187 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
1189 if (cpl_error_get_code() != CPL_ERROR_NONE)
1190 fors_pmos_science_exit(
"Missing keyword ESO DET WIN1 BINX in "
1191 "scientific frame header", nscience);
1194 dispersion *= rebin;
1195 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
1196 "spectral dispersion used is %f A/pixel", rebin,
1198 ext_radius /= rebin;
1199 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
1200 "extraction radius used is %d pixel", rebin,
1204 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
1206 if (cpl_error_get_code() != CPL_ERROR_NONE)
1207 fors_pmos_science_exit(
"Missing keyword ESO DET OUT1 CONAD in "
1208 "scientific frame header", nscience);
1210 cpl_msg_info(recipe,
"The gain factor is: %.2f e-/ADU", gain);
1212 ron = cpl_propertylist_get_double(header,
"ESO DET OUT1 RON");
1214 if (cpl_error_get_code() != CPL_ERROR_NONE)
1215 fors_pmos_science_exit(
"Missing keyword ESO DET OUT1 RON in "
1216 "scientific frame header", nscience);
1220 cpl_msg_info(recipe,
"The read-out-noise is: %.2f ADU", ron);
1222 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
1223 cpl_msg_error(recipe,
"Missing required input: %s", curv_coeff_tag);
1224 fors_pmos_science_exit(NULL, nscience);
1227 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
1228 cpl_msg_error(recipe,
"Too many in input: %s", curv_coeff_tag);
1229 fors_pmos_science_exit(NULL, nscience);
1232 cpl_msg_info(recipe,
"Load normalised flat field (if present)...");
1233 cpl_msg_indent_more();
1237 CPL_TYPE_FLOAT, 0, 1);
1240 if (skyalign >= 0) {
1242 cpl_msg_indent_less();
1243 cpl_msg_info(recipe,
"Load input sky line catalog...");
1244 cpl_msg_indent_more();
1253 nlines = cpl_table_get_nrow(wavelengths);
1256 fors_pmos_science_exit(
"Empty input sky line catalog", nscience);
1258 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
1259 cpl_msg_error(recipe,
"Missing column %s in input line "
1260 "catalog table", wcolumn);
1261 fors_pmos_science_exit(NULL, nscience);
1264 line = cpl_malloc(nlines *
sizeof(
double));
1266 for (i = 0; i < nlines; i++)
1267 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
1269 cpl_table_delete(wavelengths); wavelengths = NULL;
1271 lines = cpl_vector_wrap(nlines, line);
1274 cpl_msg_info(recipe,
"No sky line catalog found in input - fine!");
1285 cpl_propertylist_delete(header); header = NULL;
1287 cpl_table_name_column(mask_science,
"xtop",
"science");
1295 if (idscoeff == NULL)
1296 fors_pmos_science_exit(
"Cannot load wavelength calibration table", nscience);
1307 cpl_propertylist_delete(header); header = NULL;
1309 if (cpl_table_move_column(mask_science,
"xtop", mask_arc)) {
1311 cpl_msg_warning(recipe,
1312 "Slit configuration of science and arc differs!");
1313 cpl_table_delete(mask_arc); mask_arc = NULL;
1316 cpl_table_name_column(mask_science,
"xtop",
"arc");
1317 cpl_table_delete(mask_arc); mask_arc = NULL;
1330 cpl_propertylist_delete(header); header = NULL;
1332 if (cpl_table_move_column(mask_science,
"xtop", mask_flat)) {
1334 cpl_msg_warning(recipe,
1335 "Slit configuration of science and flat differs!");
1336 cpl_table_delete(mask_flat); mask_flat = NULL;
1339 cpl_table_name_column(mask_science,
"xtop",
"flat");
1340 cpl_table_delete(mask_flat); mask_flat = NULL;
1343 cpl_table_duplicate_column(mask_science,
"diff", mask_science,
"science");
1344 cpl_table_subtract_columns(mask_science,
"diff",
"arc");
1345 cpl_table_abs_column(mask_science,
"diff");
1347 if (cpl_table_get_column_max(mask_science,
"diff") > 0.01) {
1348 cpl_msg_warning(recipe,
1349 "Slit configuration of science and arc differs!");
1354 cpl_table_erase_column(mask_science,
"diff");
1356 cpl_table_duplicate_column(mask_science,
"diff",
1357 mask_science,
"science");
1358 cpl_table_subtract_columns(mask_science,
"diff",
"flat");
1359 cpl_table_abs_column(mask_science,
"diff");
1361 if (cpl_table_get_column_max(mask_science,
"diff") > 0.01) {
1362 cpl_msg_warning(recipe,
1363 "Slit configuration of science and flat differs!");
1370 cpl_table_delete(mask_science); mask_science = NULL;
1372 for (j = 0; j < nscience; j++) {
1375 cpl_msg_indent_less();
1376 cpl_msg_info(recipe,
"Processing scientific exposure of angle %.2f "
1377 "(%d out of %d) ...",
1378 angles[j], j + 1, nscience);
1379 cpl_msg_indent_more();
1381 cpl_msg_info(recipe,
"Load scientific exposure...");
1382 cpl_msg_indent_more();
1393 for (k = 0; k < j; k ++) {
1394 cpl_propertylist_delete(header);
1398 spectra =
dfs_load_image(frameset, science_tag, CPL_TYPE_FLOAT, 0, 0);
1400 for (k = 0; k < j; k ++) {
1401 cpl_image_delete(spectra);
1405 if (spectra == NULL)
1406 fors_pmos_science_exit(
"Cannot load scientific frame", nscience);
1409 fors_pmos_science_exit(
"Cannot load scientific frame header", nscience);
1411 alltime = cpl_propertylist_get_double(header,
"EXPTIME");
1413 if (cpl_error_get_code() != CPL_ERROR_NONE)
1414 fors_pmos_science_exit(
"Missing keyword EXPTIME in scientific "
1415 "frame header", nscience);
1417 cpl_msg_info(recipe,
"Scientific frame exposure time: %.2f s",
1420 ra = cpl_propertylist_get_double(header,
"RA");
1421 dec = cpl_propertylist_get_double(header,
"DEC");
1423 if (cpl_error_get_code() != CPL_ERROR_NONE)
1424 fors_pmos_science_exit(
"Missing keywords RA and DEC in scientific "
1425 "frame header", nscience);
1429 cpl_msg_indent_less();
1435 cpl_msg_info(recipe,
"Remove the master bias...");
1437 bias =
dfs_load_image(frameset,
"MASTER_BIAS", CPL_TYPE_FLOAT, 0, 1);
1440 fors_pmos_science_exit(
"Cannot load master bias", nscience);
1444 blevel = cpl_image_get_mean(bias);
1448 overscans = mos_load_overscans_fors(header);
1451 cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
1452 cpl_image_delete(bias); bias = NULL;
1453 cpl_table_delete(overscans); overscans = NULL;
1455 if (spectra == NULL)
1456 fors_pmos_science_exit(
"Cannot remove bias from scientific frame", nscience);
1458 ccd_xsize = nx = cpl_image_get_size_x(spectra);
1459 ccd_ysize = ny = cpl_image_get_size_y(spectra);
1464 cpl_msg_info(recipe,
"Apply flat field correction...");
1465 if (cpl_image_divide(spectra, norm_flat) != CPL_ERROR_NONE) {
1466 cpl_msg_error(recipe,
1467 "Failure of flat field correction: %s",
1468 cpl_error_get_message());
1469 fors_pmos_science_exit(NULL, nscience);
1473 cpl_msg_error(recipe,
"Cannot load input %s for flat field "
1474 "correction", master_norm_flat_tag);
1475 fors_pmos_science_exit(NULL, nscience);
1485 if (polytraces == NULL)
1486 fors_pmos_science_exit(
"Cannot load spectral curvature table", nscience);
1494 fors_pmos_science_exit(
"Cannot load slits location table", nscience);
1496 cpl_msg_info(recipe,
"Processing scientific spectra...");
1503 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1506 reference, startwavelength,
1507 endwavelength, dispersion,
1518 if (dispersion > 1.0)
1523 if (skyalign >= 0) {
1525 cpl_msg_info(recipe,
1526 "Align wavelength solution to reference skylines "
1527 "applying %d order residual fit...", skyalign);
1530 cpl_msg_info(recipe,
"Align wavelength solution to reference "
1531 "skylines applying median offset...");
1536 startwavelength, endwavelength,
1537 idscoeff, lines, highres,
1538 skyalign, rainbow, 4);
1541 cpl_msg_warning(recipe,
"Alignment of the wavelength "
1542 "solution to reference sky lines may "
1543 "be unreliable in this case!");
1546 NULL, parlist, recipe, version)) {
1547 fors_pmos_science_exit(NULL, nscience);
1551 cpl_msg_warning(recipe,
"Alignment of the wavelength "
1552 "solution to reference sky lines could "
1562 polytraces, reference,
1563 startwavelength, endwavelength,
1567 cpl_image_delete(rainbow); rainbow = NULL;
1568 cpl_image_delete(coordinate); coordinate = NULL;
1576 startwavelength, endwavelength,
1577 dispersion, idscoeff, flux);
1580 cpl_msg_indent_less();
1581 cpl_msg_info(recipe,
1582 "Check applied wavelength against skylines...");
1583 cpl_msg_indent_more();
1586 dispersion, 6, highres);
1589 cpl_msg_info(recipe,
"Mean residual: %f", mean_rms);
1591 mean_rms = cpl_table_get_column_mean(idscoeff,
"error");
1593 cpl_msg_info(recipe,
"Mean model accuracy: %f pixel (%f A)",
1594 mean_rms, mean_rms * dispersion);
1597 save_header = cpl_propertylist_duplicate(header);
1599 cpl_propertylist_update_double(header,
"CRPIX1", 1.0);
1600 cpl_propertylist_update_double(header,
"CRPIX2", 1.0);
1601 cpl_propertylist_update_double(header,
"CRVAL1",
1602 startwavelength + dispersion/2);
1603 cpl_propertylist_update_double(header,
"CRVAL2", 1.0);
1604 cpl_propertylist_update_double(header,
"CD1_1", dispersion);
1605 cpl_propertylist_update_double(header,
"CD1_2", 0.0);
1606 cpl_propertylist_update_double(header,
"CD2_1", 0.0);
1607 cpl_propertylist_update_double(header,
"CD2_2", 1.0);
1608 cpl_propertylist_update_string(header,
"CTYPE1",
"LINEAR");
1609 cpl_propertylist_update_string(header,
"CTYPE2",
"PIXEL");
1611 if (time_normalise) {
1612 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
1616 mapped_science_sky_tag,
1618 fors_pmos_science_exit(NULL, nscience);
1623 fors_pmos_science_exit(NULL, nscience);
1626 cpl_image_delete(dummy); dummy = NULL;
1632 mapped_science_sky_tag,
1634 fors_pmos_science_exit(NULL, nscience);
1639 mapped_science_sky_tag, header)) {
1640 fors_pmos_science_exit(NULL, nscience);
1645 if (skymedian == 0 && skylocal == 0) {
1646 cpl_image_delete(mapped_sky); mapped_sky = NULL;
1651 cpl_msg_indent_less();
1653 cpl_msg_info(recipe,
"Local sky determination...");
1654 cpl_msg_indent_more();
1656 startwavelength, endwavelength, dispersion);
1660 cpl_image_divide_scalar(skymap, alltime);
1666 fors_pmos_science_exit(NULL, nscience);
1672 fors_pmos_science_exit(NULL, nscience);
1675 cpl_image_delete(skymap); skymap = NULL;
1679 unmapped_science_tag,
1681 fors_pmos_science_exit(NULL, nscience);
1687 fors_pmos_science_exit(NULL, nscience);
1691 cpl_msg_info(recipe,
"Removing cosmic rays...");
1700 cpl_image_delete(smapped); smapped = NULL;
1703 reference, startwavelength,
1704 endwavelength, dispersion,
1708 cpl_msg_warning(recipe,
"Sky subtraction failure");
1710 cpl_msg_warning(recipe,
1711 "Cosmic rays removal not performed!");
1712 cosmics = skylocal = 0;
1716 cpl_image_delete(spectra); spectra = NULL;
1717 cpl_table_delete(polytraces); polytraces = NULL;
1719 if (skyalign >= 0) {
1724 wavelength_map_sky_tag,
1726 fors_pmos_science_exit(NULL, nscience);
1732 fors_pmos_science_exit(NULL, nscience);
1736 cpl_image_delete(wavemap); wavemap = NULL;
1739 startwavelength, endwavelength,
1740 dispersion, idscoeff, flux);
1742 cpl_image_delete(smapped); smapped = NULL;
1744 if (skyalign >= 0) {
1747 NULL, parlist, recipe, version)) {
1748 fors_pmos_science_exit(NULL, nscience);
1754 cpl_msg_indent_less();
1755 cpl_msg_info(recipe,
"Local sky determination...");
1756 cpl_msg_indent_more();
1759 cpl_image_subtract(mapped, skylocalmap);
1760 cpl_image_delete(skylocalmap); skylocalmap = NULL;
1763 if (skymedian || skylocal) {
1765 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
1767 cpl_image_delete(mapped_sky); mapped_sky = NULL;
1769 if (time_normalise) {
1770 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
1776 fors_pmos_science_exit(NULL, nscience);
1782 fors_pmos_science_exit(NULL, nscience);
1785 cpl_image_delete(dummy); dummy = NULL;
1792 fors_pmos_science_exit(NULL, nscience);
1798 fors_pmos_science_exit(NULL, nscience);
1802 skylocalmaps[j] = skylocalmap;
1804 cpl_msg_indent_less();
1805 cpl_msg_info(recipe,
"Object detection...");
1806 cpl_msg_indent_more();
1809 origslits = cpl_table_duplicate(slits);
1810 nslits = cpl_table_get_nrow(slits);
1813 if (cosmics || nscience > 1) {
1815 ext_radius, cont_radius);
1818 mapped_cleaned = cpl_image_duplicate(mapped);
1821 ext_radius, cont_radius);
1823 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
1826 cpl_image_delete(dummy); dummy = NULL;
1831 mappeds[j] = mapped;
1833 cpl_msg_indent_less();
1835 cpl_propertylist_delete(header); header = NULL;
1836 cpl_propertylist_delete(save_header); save_header = NULL;
1839 cpl_table_delete(offsets); offsets = NULL;
1840 cpl_table_delete(idscoeff); idscoeff = NULL;
1842 cpl_image_delete(norm_flat); norm_flat = NULL;
1843 cpl_vector_delete(lines); lines = NULL;
1846 cpl_msg_indent_less();
1847 cpl_msg_info(recipe,
1848 "Check object detection in both beams for all angles...");
1849 cpl_msg_indent_more();
1857 if (error == CPL_ERROR_DATA_NOT_FOUND) {
1858 cpl_msg_warning(recipe,
"No objects found: no Stokes "
1859 "parameters to compute!");
1860 for (j = 0; j < nscience; j++)
1861 cpl_table_delete(slitss[j]);
1863 cpl_table_delete(origslits);
1866 fors_pmos_science_exit(
"Problem in polarimetric object selection", nscience);
1870 NULL, parlist, recipe, version)) {
1871 fors_pmos_science_exit(NULL, nscience);
1878 for (j = 0; j < nscience; j++) {
1882 fors_pmos_science_exit(NULL, nscience);
1887 fors_pmos_science_exit(NULL, nscience);
1891 nobjs_per_slit = fors_get_nobjs_perslit(origslits);
1893 cpl_msg_indent_less();
1894 cpl_msg_info(recipe,
"Object extraction...");
1895 cpl_msg_indent_more();
1897 for (j = 0; j < nscience; j++) {
1902 for (k = 0; k < j; k ++) {
1903 cpl_propertylist_delete(header);
1907 cpl_propertylist_update_double(header,
"CRPIX1", 1.0);
1908 cpl_propertylist_update_double(header,
"CRPIX2", 1.0);
1909 cpl_propertylist_update_double(header,
"CRVAL1",
1910 startwavelength + (dispersion * group)/2);
1911 cpl_propertylist_update_double(header,
"CRVAL2", 1.0);
1912 cpl_propertylist_update_double(header,
"CD1_1", dispersion * group);
1913 cpl_propertylist_update_double(header,
"CD1_2", 0.0);
1914 cpl_propertylist_update_double(header,
"CD2_1", 0.0);
1915 cpl_propertylist_update_double(header,
"CD2_2", 1.0);
1916 cpl_propertylist_update_string(header,
"CTYPE1",
"LINEAR");
1917 cpl_propertylist_update_string(header,
"CTYPE2",
"PIXEL");
1919 if (skymedian || skylocal) {
1921 cpl_msg_info(recipe,
"Extracting at angle %.2f (%d out of %d) ...",
1922 angles[j], j + 1, nscience);
1926 ext_mode, ron, gain, 1);
1928 cpl_image_delete(skylocalmaps[j]); skylocalmaps[j] = NULL;
1932 cpl_image_divide_scalar(images[0], alltime);
1934 mos_rebin_signal(images, group);
1938 reduced_science_tag,
1940 fors_pmos_science_exit(NULL, nscience);
1946 fors_pmos_science_exit(NULL, nscience);
1949 reduceds[j] = images[0];
1952 cpl_image_divide_scalar(images[1], alltime);
1954 mos_rebin_signal(images + 1, group);
1960 fors_pmos_science_exit(NULL, nscience);
1966 fors_pmos_science_exit(NULL, nscience);
1968 cpl_image_delete(images[1]);
1971 cpl_image_divide_scalar(images[2], alltime);
1973 mos_rebin_error(images + 2, group);
1979 fors_pmos_science_exit(NULL, nscience);
1985 fors_pmos_science_exit(NULL, nscience);
1988 rerrors[j] = images[2];
1993 cpl_msg_warning(recipe,
"No objects found: the products "
1994 "%s, %s, and %s are not created",
1995 reduced_science_tag, reduced_sky_tag,
2001 if (skymedian || skylocal) {
2003 cpl_image_divide_scalar(mappeds[j], alltime);
2009 fors_pmos_science_exit(NULL, nscience);
2015 fors_pmos_science_exit(NULL, nscience);
2019 cpl_image_delete(mappeds[j]); mappeds[j] = NULL;
2020 cpl_propertylist_delete(header); header = NULL;
2024 cpl_table_delete(origslits);
2028 nobjects = cpl_image_get_size_y(reduceds[0]) / 2;
2029 nx = cpl_image_get_size_x(reduceds[0]);
2031 header = cpl_propertylist_new();
2032 cpl_propertylist_update_double(header,
"CRPIX1", 1.0);
2033 cpl_propertylist_update_double(header,
"CRPIX2", 1.0);
2034 cpl_propertylist_update_double(header,
"CRVAL1",
2035 startwavelength + (dispersion * group)/2);
2036 cpl_propertylist_update_double(header,
"CRVAL2", 1.0);
2037 cpl_propertylist_update_double(header,
"CD1_1", dispersion * group);
2038 cpl_propertylist_update_double(header,
"CD1_2", 0.0);
2039 cpl_propertylist_update_double(header,
"CD2_1", 0.0);
2040 cpl_propertylist_update_double(header,
"CD2_2", 1.0);
2041 cpl_propertylist_update_string(header,
"CTYPE1",
"LINEAR");
2042 cpl_propertylist_update_string(header,
"CTYPE2",
"PIXEL");
2046 cpl_image *pv_im = NULL;
2047 cpl_image *pi_im = NULL;
2048 cpl_image *pvnull_im = NULL;
2049 cpl_image *pierr_im = NULL;
2050 cpl_image *perr_im = NULL;
2054 double *p_vnull = NULL;
2055 double *perr = NULL;
2056 double *pierr = NULL;
2063 pv_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2064 perr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2065 pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2066 pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2068 p_v = cpl_image_get_data_double(pv_im);
2069 perr = cpl_image_get_data_double(perr_im);
2070 p_i = cpl_image_get_data_double(pi_im);
2071 pierr = cpl_image_get_data_double(pierr_im);
2073 if (nscience / 2 > 1) {
2074 pvnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2075 p_vnull = cpl_image_get_data_double(pvnull_im);
2078 for (j = 0; j < nobjects; j++) {
2085 double * ip_v, * ip_i, * ipierr,
2086 * ip_vnull, * iperr;
2089 float * iff, * ierr;
2091 ip_v = p_v + (nobjects - 1 - j) * nx;
2093 if (nscience / 2 > 1)
2094 ip_vnull = p_vnull + (nobjects - 1 - j) * nx;
2096 iperr = perr + (nobjects - 1 - j) * nx;
2098 ip_i = p_i + (nobjects - 1 - j) * nx;
2099 ipierr = pierr + (nobjects - 1 - j) * nx;
2102 for (i = 0; i < nslits; i += 2) {
2103 total += nobjs_per_slit[i];
2110 for (k = 0; k < nscience / 2; k++) {
2111 float *if_o, *if_e, *ifdelta_o, *ifdelta_e;
2112 float *if_o_err, *if_e_err, *ifdelta_o_err, *ifdelta_e_err;
2114 int pos = fors_find_angle_pos(angles, nscience, 180 * k - 45);
2115 int pos_d = fors_find_angle_pos(angles, nscience, 180 * k + 45);
2118 data = cpl_image_get_data_float(reduceds[pos]);
2120 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2121 + (total - j - 1)) * nx;
2123 if_e = data + (2 * (nobjects - total)
2124 + (total - j - 1)) * nx;
2126 data = cpl_image_get_data_float(reduceds[pos_d]);
2128 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2129 + (total - j - 1)) * nx;
2131 ifdelta_e = data + (2 * (nobjects - total)
2132 + (total - j - 1)) * nx;
2134 data = cpl_image_get_data_float(rerrors[pos]);
2137 + (2 * (nobjects - total) + nobjs_per_slit[p]
2138 + (total - j - 1)) * nx;
2140 if_e_err = data + (2 * (nobjects - total)
2141 + (total - j - 1)) * nx;
2143 data = cpl_image_get_data_float(rerrors[pos_d]);
2145 ifdelta_o_err = data
2146 + (2 * (nobjects - total) + nobjs_per_slit[p]
2147 + (total - j - 1)) * nx;
2149 ifdelta_e_err = data + (2 * (nobjects - total)
2150 + (total - j - 1)) * nx;
2154 char *signal_to_noise = getenv(
"SIGNAL_TO_NOISE" );
2156 char *min_s2n = getenv(
"MIN_S2N" );
2159 if (signal_to_noise)
2160 s2n = atof(signal_to_noise);
2163 ms2n = atoi(min_s2n);
2172 for (m = 0; m < nx; m++) {
2173 if (if_o_err[m] > 0.0) {
2174 if (if_o[m]/if_o_err[m] > s2n) {
2176 if (bright > ms2n) {
2184 if (bright > ms2n) {
2186 filename = cpl_sprintf(
"angle_%d_%d.dat",
2188 file = fopen(filename,
"w");
2190 fprintf(file,
"%d\n", p + 2);
2192 for (m = 0; m < nx; m++) {
2193 double lambda = startwavelength
2194 + dispersion * group * (0.5 + m);
2195 fprintf(file,
"%.3f %.9e %.9e %.9e %.9e\n",
2196 lambda, if_o[m], if_o_err[m],
2197 if_e[m], if_e_err[m]);
2203 filename = cpl_sprintf(
"angle_%d_%d.dat",
2205 file = fopen(filename,
"w");
2207 fprintf(file,
"%d\n", p + 2);
2209 for (m = 0; m < nx; m++) {
2210 double lambda = startwavelength
2211 + dispersion * group * (0.5 + m);
2212 fprintf(file,
"%.3f %.9e %.9e %.9e %.9e\n",
2213 lambda, ifdelta_o[m], ifdelta_o_err[m],
2214 ifdelta_e[m], ifdelta_e_err[m]);
2221 cpl_msg_info(recipe,
2222 "Extracted signal not written to "
2223 "ASCII (S/N > %.0f only in %d < %d "
2224 "bins)", s2n, bright, ms2n);
2228 for (m = 0; m < nx; m++) {
2230 double quantity = if_o[m] + if_e[m] == 0.0 ? 0.0 :
2231 (if_o[m] - if_e[m] ) /
2232 (if_o[m] + if_e[m] ) -
2233 (ifdelta_o[m] - ifdelta_e[m]) /
2234 (ifdelta_o[m] + ifdelta_e[m]);
2236 quantity = isfinite(quantity) ? quantity : 0.0;
2239 ip_v[m] += quantity * 0.5 / (nscience / 2);
2242 if (nscience / 2 > 1) {
2244 ip_vnull[m] += quantity * 0.5 / (nscience / 2);
2246 ip_vnull[m] -= quantity * 0.5 / (nscience / 2);
2250 ip_i[m] += (if_o[m] + if_e[m] +
2251 ifdelta_o[m] + ifdelta_e[m]) / nscience;
2254 ipierr[m] += (if_o_err[m] * if_o_err[m]
2255 + if_e_err[m] * if_e_err[m]
2256 + ifdelta_o_err[m] * ifdelta_o_err[m]
2257 + ifdelta_e_err[m] * ifdelta_e_err[m])
2258 / nscience / nscience;
2264 data = cpl_image_get_data_float(reduceds[0]);
2265 iff = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2267 data = cpl_image_get_data_float(rerrors[0]);
2268 ierr = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2270 for (m = 0; m < nx; m++)
2271 iperr[m] = iff[m] <= 0.0 ?
2272 0.0 : ierr[m] / iff[m] * 0.5 / sqrt (nscience / 2);
2274 if (nscience / 2 > 1) {
2276 float max, sum, sum2, imean;
2281 weights = cpl_malloc(
sizeof(
float) * nx);
2284 for (k = 0; k < nx; k++) {
2285 if (max < iff[k]) max = iff[k];
2288 for (k = 0; k < nx; k++) {
2289 weights[k] = iff[k] < 0.0 ?
2290 0.0 : iff[k] * iff[k] / (max * max);
2295 for (k = 0; k < nx; k++) {
2296 sum += weights[k] * ip_vnull[k];
2304 mean_vnull += (imean - mean_vnull) / (j + 1.0);
2309 parlist, recipe, version))
2310 fors_pmos_science_exit(NULL, nscience);
2313 parlist, recipe, version))
2314 fors_pmos_science_exit(NULL, nscience);
2316 if (nscience / 2 > 1) {
2319 cpl_propertylist *qheader;
2322 cpl_propertylist_update_double(qheader,
"CRPIX1", 1.0);
2323 cpl_propertylist_update_double(qheader,
"CRPIX2", 1.0);
2324 cpl_propertylist_update_double(qheader,
"CRVAL1",
2325 startwavelength + (dispersion * group)/2);
2326 cpl_propertylist_update_double(qheader,
"CRVAL2", 1.0);
2327 cpl_propertylist_update_double(qheader,
"CD1_1",
2328 dispersion * group);
2329 cpl_propertylist_update_double(qheader,
"CD1_2", 0.0);
2330 cpl_propertylist_update_double(qheader,
"CD2_1", 0.0);
2331 cpl_propertylist_update_double(qheader,
"CD2_2", 1.0);
2332 cpl_propertylist_update_string(qheader,
"CTYPE1",
"LINEAR");
2333 cpl_propertylist_update_string(qheader,
"CTYPE2",
"PIXEL");
2343 "Product category", instrume))
2344 fors_pmos_science_exit(
"Cannot write product category to "
2345 "QC log file", nscience);
2348 "DPR type", instrume))
2349 fors_pmos_science_exit(
"Missing keyword DPR TYPE in "
2350 "scientific frame header", nscience);
2353 "Template", instrume))
2354 fors_pmos_science_exit(
"Missing keyword TPL ID in "
2355 "scientific frame header", nscience);
2358 "Grism name", instrume))
2359 fors_pmos_science_exit(
"Missing keyword INS GRIS1 NAME in "
2360 "scientific frame header", nscience);
2363 "Grism identifier", instrume))
2364 fors_pmos_science_exit(
"Missing keyword INS GRIS1 ID in "
2365 "scientific frame header", nscience);
2367 if (cpl_propertylist_has(qheader,
"ESO INS FILT1 NAME"))
2369 "Filter name", instrume);
2372 "Collimator name", instrume))
2373 fors_pmos_science_exit(
"Missing keyword INS COLL NAME in "
2374 "scientific frame header", nscience);
2377 "Chip identifier", instrume))
2378 fors_pmos_science_exit(
"Missing keyword DET CHIP1 ID in "
2379 "scientific frame header", nscience);
2382 "Archive name of input data",
2384 fors_pmos_science_exit(
"Missing keyword ARCFILE in "
2385 "scientific frame header", nscience);
2387 pipefile = dfs_generate_filename(reduced_nul_v_tag);
2389 "Pipeline product name", instrume))
2390 fors_pmos_science_exit(
"Cannot write PIPEFILE to "
2391 "QC log file", nscience);
2392 cpl_free(pipefile); pipefile = NULL;
2399 keyname =
"QC.NULL.V.MEAN";
2403 "Mean V null parameter",
2405 fors_pmos_science_exit(
"Cannot write mean Q null "
2406 "parameter to QC log file.", nscience);
2409 keyname =
"QC.NANGLES";
2411 if (fors_qc_write_qc_int(qheader, nscience,
2413 "Number of processed plate angles",
2415 fors_pmos_science_exit(
"Cannot write number of processed "
2416 "plate angles.", nscience);
2422 if (
dfs_save_image(frameset, pvnull_im, reduced_nul_v_tag, qheader,
2423 parlist, recipe, version))
2424 fors_pmos_science_exit(NULL, nscience);
2426 cpl_propertylist_delete(qheader);
2429 if (
dfs_save_image(frameset, perr_im, reduced_error_v_tag, header,
2430 parlist, recipe, version))
2431 fors_pmos_science_exit(NULL, nscience);
2433 cpl_image_power(pierr_im, 0.5);
2435 if (
dfs_save_image(frameset, pierr_im, reduced_error_i_tag, header,
2436 parlist, recipe, version))
2437 fors_pmos_science_exit(NULL, nscience);
2439 cpl_image_delete(pv_im);
2440 cpl_image_delete(pvnull_im);
2441 cpl_image_delete(perr_im);
2442 cpl_image_delete(pi_im);
2443 cpl_image_delete(pierr_im);
2446 cpl_image *pq_im = NULL;
2447 cpl_image *pu_im = NULL;
2448 cpl_image *pl_im = NULL;
2449 cpl_image *pi_im = NULL;
2451 cpl_image *pqnull_im = NULL;
2452 cpl_image *punull_im = NULL;
2454 cpl_image *pqerr_im = NULL;
2455 cpl_image *puerr_im = NULL;
2456 cpl_image *plerr_im = NULL;
2457 cpl_image *pierr_im = NULL;
2459 cpl_image *pang_im = NULL;
2460 cpl_image *pangerr_im = NULL;
2467 double *p_qnull = NULL;
2468 double *p_unull = NULL;
2470 double *pqerr = NULL;
2471 double *puerr = NULL;
2472 double *plerr = NULL;
2473 double *pierr = NULL;
2475 double *pang = NULL;
2476 double *pangerr = NULL;
2480 cpl_image *correct_im = cpl_image_new(nx, 1, CPL_TYPE_DOUBLE);
2481 double *correct = cpl_image_get_data_double(correct_im);
2483 double mean_unull, mean_qnull;
2488 pq_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2489 pu_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2490 pl_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2491 pi_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2493 pqerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2494 puerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2495 plerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2496 pierr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2498 pang_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2499 pangerr_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2501 p_q = cpl_image_get_data_double(pq_im);
2502 p_u = cpl_image_get_data_double(pu_im);
2503 p_l = cpl_image_get_data_double(pl_im);
2504 p_i = cpl_image_get_data_double(pi_im);
2506 if (nscience / 4 > 1) {
2507 pqnull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2508 punull_im = cpl_image_new(nx, nobjects, CPL_TYPE_DOUBLE);
2510 p_qnull = cpl_image_get_data_double(pqnull_im);
2511 p_unull = cpl_image_get_data_double(punull_im);
2513 cpl_msg_warning(cpl_func,
2514 "Not enough pairs to compute null parameters");
2517 pqerr = cpl_image_get_data_double(pqerr_im);
2518 puerr = cpl_image_get_data_double(puerr_im);
2519 plerr = cpl_image_get_data_double(plerr_im);
2520 pierr = cpl_image_get_data_double(pierr_im);
2522 pang = cpl_image_get_data_double(pang_im);
2523 pangerr = cpl_image_get_data_double(pangerr_im);
2526 cpl_table * chrotbl =
2529 int nrow = cpl_table_get_nrow(chrotbl);
2530 float * lambda = cpl_table_get_data_float(chrotbl,
"lambda");
2531 float * theta = cpl_table_get_data_float(chrotbl,
"eps_theta");
2533 for (j = 0; j < nx; j++) {
2534 double c_wave = startwavelength
2535 + (dispersion * group) / 2
2536 + j * dispersion * group;
2540 for (k = 0; k < nrow - 1; k++) {
2541 if (lambda[k] <= c_wave && c_wave < lambda[k + 1]) {
2548 correct[j] = (theta [k + 1] - theta [k]) /
2549 (lambda[k + 1] - lambda[k]) *
2550 (c_wave - lambda[k]) + theta[k];
2551 correct[j] *= M_PI / 180;
2554 correct[j] = correct[j-1];
2559 cpl_table_delete(chrotbl);
2562 for (j = 0; j < nobjects; j++) {
2584 ip_q = p_q + (nobjects - 1 - j) * nx;
2585 ip_u = p_u + (nobjects - 1 - j) * nx;
2586 ip_l = p_l + (nobjects - 1 - j) * nx;
2587 ip_i = p_i + (nobjects - 1 - j) * nx;
2589 if (nscience / 4 > 1) {
2590 ip_qnull = p_qnull + (nobjects - 1 - j) * nx;
2591 ip_unull = p_unull + (nobjects - 1 - j) * nx;
2594 ipqerr = pqerr + (nobjects - 1 - j) * nx;
2595 ipuerr = puerr + (nobjects - 1 - j) * nx;
2596 iplerr = plerr + (nobjects - 1 - j) * nx;
2597 ipierr = pierr + (nobjects - 1 - j) * nx;
2599 ipang = pang + (nobjects - 1 - j) * nx;
2600 ipangerr = pangerr + (nobjects - 1 - j) * nx;
2603 for (i = 0; i < nslits; i += 2) {
2604 total += nobjs_per_slit[i];
2611 for (k = 0; k < nscience / 4; k++) {
2612 float * if_o, * if_e, * ifdelta_o, * ifdelta_e;
2613 float * if_o_err, * if_e_err, * ifdelta_o_err, * ifdelta_e_err;
2617 pos = fors_find_angle_pos(angles, nscience, 90 * k);
2618 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 45);
2620 data = cpl_image_get_data_float(reduceds[pos]);
2622 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2623 + (total - j - 1)) * nx;
2625 if_e = data + (2 * (nobjects - total)
2626 + (total - j - 1)) * nx;
2628 data = cpl_image_get_data_float(reduceds[pos_d]);
2630 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2631 + (total - j - 1)) * nx;
2633 ifdelta_e = data + (2 * (nobjects - total)
2634 + (total - j - 1)) * nx;
2636 data = cpl_image_get_data_float(rerrors[pos]);
2638 if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2639 + (total - j - 1)) * nx;
2641 if_e_err = data + (2 * (nobjects - total)
2642 + (total - j - 1)) * nx;
2644 data = cpl_image_get_data_float(rerrors[pos_d]);
2646 ifdelta_o_err = data + (2 * (nobjects - total)
2647 + nobjs_per_slit[p] + (total - j - 1)) * nx;
2649 ifdelta_e_err = data + (2 * (nobjects - total)
2650 + (total - j - 1)) * nx;
2652 for (m = 0; m < nx; m++) {
2654 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2655 (if_o[m] - if_e[m] ) /
2656 (if_o[m] + if_e[m] ) -
2657 (ifdelta_o[m] - ifdelta_e[m]) /
2658 (ifdelta_o[m] + ifdelta_e[m]);
2660 quantity = isfinite(quantity) ? quantity : 0.0;
2663 ip_q[m] += quantity * 0.5 / (nscience / 4);
2666 if (nscience / 4 > 1) {
2668 ip_qnull[m] += quantity * 0.5 / (nscience / 4);
2670 ip_qnull[m] -= quantity * 0.5 / (nscience / 4);
2674 ip_i[m] += (if_o[m] + if_e[m] +
2675 ifdelta_o[m] + ifdelta_e[m]) / nscience;
2678 ipierr[m] += (if_o_err[m] * if_o_err[m]
2679 + if_e_err[m] * if_e_err[m]
2680 + ifdelta_o_err[m] * ifdelta_o_err[m]
2681 + ifdelta_e_err[m] * ifdelta_e_err[m])
2682 / nscience / nscience;
2687 pos = fors_find_angle_pos(angles, nscience, 90 * k + 22.5);
2688 pos_d = fors_find_angle_pos(angles, nscience, 90 * k + 67.5);
2690 data = cpl_image_get_data_float(reduceds[pos]);
2692 if_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2693 + (total - j - 1)) * nx;
2695 if_e = data + (2 * (nobjects - total)
2696 + (total - j - 1)) * nx;
2698 data = cpl_image_get_data_float(reduceds[pos_d]);
2700 ifdelta_o = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2701 + (total - j - 1)) * nx;
2703 ifdelta_e = data + (2 * (nobjects - total)
2704 + (total - j - 1)) * nx;
2706 data = cpl_image_get_data_float(rerrors[pos]);
2708 if_o_err = data + (2 * (nobjects - total) + nobjs_per_slit[p]
2709 + (total - j - 1)) * nx;
2711 if_e_err = data + (2 * (nobjects - total)
2712 + (total - j - 1)) * nx;
2714 data = cpl_image_get_data_float(rerrors[pos_d]);
2716 ifdelta_o_err = data + (2 * (nobjects - total)
2717 + nobjs_per_slit[p] + (total - j - 1)) * nx;
2719 ifdelta_e_err = data + (2 * (nobjects - total)
2720 + (total - j - 1)) * nx;
2722 for (m = 0; m < nx; m++) {
2724 double quantity = fabs(if_o[m] + if_e[m]) < FLT_MIN ? 0.0 :
2725 (if_o[m] - if_e[m] ) /
2726 (if_o[m] + if_e[m] ) -
2727 (ifdelta_o[m] - ifdelta_e[m]) /
2728 (ifdelta_o[m] + ifdelta_e[m]);
2730 quantity = isfinite(quantity) ? quantity : 0.0;
2733 ip_u[m] += quantity * 0.5 / (nscience / 4);
2736 if (nscience / 4 > 1) {
2738 ip_unull[m] += quantity * 0.5 / (nscience / 4);
2740 ip_unull[m] -= quantity * 0.5 / (nscience / 4);
2744 ip_i[m] += (if_o[m] + if_e[m] +
2745 ifdelta_o[m] + ifdelta_e[m]) / nscience;
2748 ipierr[m] += (if_o_err[m] * if_o_err[m]
2749 + if_e_err[m] * if_e_err[m]
2750 + ifdelta_o_err[m] * ifdelta_o_err[m]
2751 + ifdelta_e_err[m] * ifdelta_e_err[m])
2752 / nscience / nscience;
2758 pos = fors_find_angle_pos(angles, nscience, 0.0);
2760 data = cpl_image_get_data_float(reduceds[pos]);
2761 iffq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2763 data = cpl_image_get_data_float(rerrors[pos]);
2764 ierrq = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2766 pos = fors_find_angle_pos(angles, nscience, 22.5);
2768 data = cpl_image_get_data_float(reduceds[pos]);
2769 iffu = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2771 data = cpl_image_get_data_float(rerrors[pos]);
2772 ierru = data + (2 * (nobjects - total) + (total - j - 1)) * nx;
2774 for (m = 0; m < nx; m++) {
2778 ipqerr[m] = iffq[m] <= 0.0 ?
2779 0.0 : ierrq[m] / iffq[m] * 0.5 / sqrt (nscience / 4);
2781 ipuerr[m] = iffu[m] <= 0.0 ?
2782 0.0 : ierru[m] / iffu[m] * 0.5 / sqrt (nscience / 4);
2784 iplerr[m] = 0.5 * (ipqerr[m] + ipuerr[m]);
2787 ip_l[m] = sqrt(ip_u[m] * ip_u[m] + ip_q[m] * ip_q[m]);
2790 if (fabs(ip_q[m]) < 0.00001) {
2791 if (ip_u[m] > 0.0) {
2799 ipang[m] = 0.5 * atan(ip_u[m] / ip_q[m]) * 180 / M_PI;
2800 if (ip_q[m] > 0.0) {
2801 if (ip_u[m] < 0.0) {
2811 radicand = ip_q[m] * ip_q[m] * ipuerr[m] * ipuerr[m] +
2812 ip_u[m] * ip_u[m] * ipqerr[m] * ipqerr[m];
2814 ipangerr[m] = (ip_l[m] == 0.0 ? 0.0 :
2815 sqrt(radicand) * 0.5 / (ip_l[m] * ip_l[m]) * 180 / M_PI);
2824 if (instrume[4] ==
'2') {
2826 double w_rotation = - wollaston * M_PI / 2;
2828 ipang[m] -= w_rotation * 180 / M_PI;
2830 ip_q[m] = ip_q[m] * cos(2 * w_rotation)
2831 + ip_u[m] * sin(2 * w_rotation);
2833 ip_u[m] = ip_u[m] * cos(2 * w_rotation)
2834 - ip_q[m] * sin(2 * w_rotation);
2838 ipang[m] -= correct[m] * 180 / M_PI;
2840 ip_q[m] = ip_q[m] * cos(2 * correct[m])
2841 + ip_u[m] * sin(2 * correct[m]);
2843 ip_u[m] = ip_u[m] * cos(2 * correct[m])
2844 - ip_q[m] * sin(2 * correct[m]);
2849 else if (ipang[m] >= 180.0)
2853 if (nscience / 4 > 1) {
2855 float max, sum, sum2, imean;
2860 weights = cpl_malloc(
sizeof(
float) * nx);
2863 for (k = 0; k < nx; k++) {
2864 if (max < iffq[k]) max = iffq[k];
2867 for (k = 0; k < nx; k++) {
2868 weights[k] = iffq[k] < 0.0 ?
2869 0.0 : iffq[k] * iffq[k] / (max * max);
2874 for (k = 0; k < nx; k++) {
2875 sum += weights[k] * ip_qnull[k];
2883 mean_qnull += (imean - mean_qnull) / (j + 1.0);
2886 weights = cpl_malloc(
sizeof(
float) * nx);
2889 for (k = 0; k < nx; k++) {
2890 if (max < iffu[k]) max = iffu[k];
2893 for (k = 0; k < nx; k++) {
2894 weights[k] = iffu[k] < 0.0 ?
2895 0.0 : iffu[k] * iffu[k] / (max * max);
2900 for (k = 0; k < nx; k++) {
2901 sum += weights[k] * ip_unull[k];
2909 mean_unull += (imean - mean_unull) / (j + 1.0);
2913 cpl_image_delete(correct_im);
2916 parlist, recipe, version))
2917 fors_pmos_science_exit(NULL, nscience);
2920 parlist, recipe, version))
2921 fors_pmos_science_exit(NULL, nscience);
2923 if (qc && standard) {
2924 cpl_table *polsta =
dfs_load_table(frameset, std_pmos_table_tag, 1);
2927 cpl_propertylist_update_double(qheader,
"CRPIX1", 1.0);
2928 cpl_propertylist_update_double(qheader,
"CRPIX2", 1.0);
2929 cpl_propertylist_update_double(qheader,
"CRVAL1",
2930 startwavelength + (dispersion * group)/2);
2931 cpl_propertylist_update_double(qheader,
"CRVAL2", 1.0);
2932 cpl_propertylist_update_double(qheader,
"CD1_1",
2933 dispersion * group);
2934 cpl_propertylist_update_double(qheader,
"CD1_2", 0.0);
2935 cpl_propertylist_update_double(qheader,
"CD2_1", 0.0);
2936 cpl_propertylist_update_double(qheader,
"CD2_2", 1.0);
2937 cpl_propertylist_update_string(qheader,
"CTYPE1",
"LINEAR");
2938 cpl_propertylist_update_string(qheader,
"CTYPE2",
"PIXEL");
2941 startwavelength, dispersion, 1000.,
2942 polsta, ra, dec, &filter,
2945 &qc_angle, &qc_angle_err)) {
2946 cpl_msg_warning(cpl_func,
"No QC can be computed");
2952 char band[] = {
' ',
'\0'};
2961 "Product category", instrume))
2962 fors_pmos_science_exit(
"Cannot write product category to "
2963 "QC log file", nscience);
2966 "DPR type", instrume))
2967 fors_pmos_science_exit(
"Missing keyword DPR TYPE in "
2968 "scientific frame header", nscience);
2971 "Template", instrume))
2972 fors_pmos_science_exit(
"Missing keyword TPL ID in "
2973 "scientific frame header", nscience);
2976 "Grism name", instrume))
2977 fors_pmos_science_exit(
"Missing keyword INS GRIS1 NAME in "
2978 "scientific frame header", nscience);
2981 "Grism identifier", instrume))
2982 fors_pmos_science_exit(
"Missing keyword INS GRIS1 ID in "
2983 "scientific frame header", nscience);
2985 if (cpl_propertylist_has(qheader,
"ESO INS FILT1 NAME"))
2987 "Filter name", instrume);
2990 "Collimator name", instrume))
2991 fors_pmos_science_exit(
"Missing keyword INS COLL NAME in "
2992 "scientific frame header", nscience);
2995 "Chip identifier", instrume))
2996 fors_pmos_science_exit(
"Missing keyword DET CHIP1 ID in "
2997 "scientific frame header", nscience);
3000 "Archive name of input data",
3002 fors_pmos_science_exit(
"Missing keyword ARCFILE in "
3003 "scientific frame header", nscience);
3005 pipefile = dfs_generate_filename(reduced_nul_q_tag);
3007 "Pipeline product name", instrume))
3008 fors_pmos_science_exit(
"Cannot write PIPEFILE to "
3009 "QC log file", nscience);
3010 cpl_free(pipefile); pipefile = NULL;
3017 keyname =
"QC.PMOS.BAND";
3021 "Band where polarisation was "
3022 "measured", instrume)) {
3023 fors_pmos_science_exit(
"Cannot write QC.PMOS.BAND "
3024 "parameter to QC log file", nscience);
3027 keyname =
"QC.PMOS.POLARISED";
3029 if (fors_qc_write_qc_int(qheader, polarised, keyname, NULL,
3030 "Polarisation is expected (1 = yes, "
3031 "0 = no)", instrume)) {
3032 fors_pmos_science_exit(
"Cannot write QC.PMOS.POLARISED "
3033 "parameter to QC log file", nscience);
3036 keyname =
"QC.PMOS.L.OFFSET";
3039 text =
"Linear polarisation relative offset";
3041 text =
"Linear polarisation offset";
3045 fors_pmos_science_exit(
"Cannot write linear polarisation "
3046 "offset to QC log file", nscience);
3049 keyname =
"QC.PMOS.L.OFFSETERR";
3052 "Error on linear polarisation offset",
3054 fors_pmos_science_exit(
"Cannot write linear polarisation "
3055 "offset error to QC log file", nscience);
3059 keyname =
"QC.PMOS.ANGLE.OFFSET";
3062 "Polarisation angle offset",
3064 fors_pmos_science_exit(
"Cannot write polarisation "
3065 "angle offset to QC log file", nscience);
3068 keyname =
"QC.PMOS.ANGLE.OFFSETERR";
3071 NULL,
"Error on polarisation "
3072 "angle offset", instrume)) {
3073 fors_pmos_science_exit(
"Cannot write polarisation "
3074 "angle offset error to QC "
3075 "log file", nscience);
3083 parlist, recipe, version))
3084 fors_pmos_science_exit(NULL, nscience);
3086 cpl_propertylist_delete(qheader);
3090 parlist, recipe, version))
3091 fors_pmos_science_exit(NULL, nscience);
3094 if (nscience / 4 > 1) {
3100 cpl_propertylist_update_double(qheader,
"CRPIX1", 1.0);
3101 cpl_propertylist_update_double(qheader,
"CRPIX2", 1.0);
3102 cpl_propertylist_update_double(qheader,
"CRVAL1",
3103 startwavelength + (dispersion * group)/2);
3104 cpl_propertylist_update_double(qheader,
"CRVAL2", 1.0);
3105 cpl_propertylist_update_double(qheader,
"CD1_1",
3106 dispersion * group);
3107 cpl_propertylist_update_double(qheader,
"CD1_2", 0.0);
3108 cpl_propertylist_update_double(qheader,
"CD2_1", 0.0);
3109 cpl_propertylist_update_double(qheader,
"CD2_2", 1.0);
3110 cpl_propertylist_update_string(qheader,
"CTYPE1",
"LINEAR");
3111 cpl_propertylist_update_string(qheader,
"CTYPE2",
"PIXEL");
3121 "Product category", instrume))
3122 fors_pmos_science_exit(
"Cannot write product category to "
3123 "QC log file", nscience);
3126 "DPR type", instrume))
3127 fors_pmos_science_exit(
"Missing keyword DPR TYPE in "
3128 "scientific frame header", nscience);
3131 "Template", instrume))
3132 fors_pmos_science_exit(
"Missing keyword TPL ID in "
3133 "scientific frame header", nscience);
3136 "Grism name", instrume))
3137 fors_pmos_science_exit(
"Missing keyword INS GRIS1 NAME in "
3138 "scientific frame header", nscience);
3141 "Grism identifier", instrume))
3142 fors_pmos_science_exit(
"Missing keyword INS GRIS1 ID in "
3143 "scientific frame header", nscience);
3145 if (cpl_propertylist_has(qheader,
"ESO INS FILT1 NAME"))
3147 "Filter name", instrume);
3150 "Collimator name", instrume))
3151 fors_pmos_science_exit(
"Missing keyword INS COLL NAME in "
3152 "scientific frame header", nscience);
3155 "Chip identifier", instrume))
3156 fors_pmos_science_exit(
"Missing keyword DET CHIP1 ID in "
3157 "scientific frame header", nscience);
3160 "Archive name of input data",
3162 fors_pmos_science_exit(
"Missing keyword ARCFILE in "
3163 "scientific frame header", nscience);
3165 pipefile = dfs_generate_filename(reduced_nul_q_tag);
3167 "Pipeline product name", instrume))
3168 fors_pmos_science_exit(
"Cannot write PIPEFILE to "
3169 "QC log file", nscience);
3170 cpl_free(pipefile); pipefile = NULL;
3177 keyname =
"QC.NULL.Q.MEAN";
3181 "Mean Q null parameter",
3183 fors_pmos_science_exit(
"Cannot write mean Q null "
3184 "parameter to QC log file", nscience);
3187 keyname =
"QC.NANGLES";
3189 if (fors_qc_write_qc_int(qheader, nscience / 2,
3191 "Number of processed plate angles",
3193 fors_pmos_science_exit(
"Cannot write number of processed "
3194 "plate angles.", nscience);
3200 if (
dfs_save_image(frameset, pqnull_im, reduced_nul_q_tag, qheader,
3201 parlist, recipe, version))
3202 fors_pmos_science_exit(NULL, nscience);
3204 cpl_propertylist_delete(qheader);
3208 cpl_propertylist_update_double(qheader,
"CRPIX1", 1.0);
3209 cpl_propertylist_update_double(qheader,
"CRPIX2", 1.0);
3210 cpl_propertylist_update_double(qheader,
"CRVAL1",
3211 startwavelength + (dispersion * group)/2);
3212 cpl_propertylist_update_double(qheader,
"CRVAL2", 1.0);
3213 cpl_propertylist_update_double(qheader,
"CD1_1",
3214 dispersion * group);
3215 cpl_propertylist_update_double(qheader,
"CD1_2", 0.0);
3216 cpl_propertylist_update_double(qheader,
"CD2_1", 0.0);
3217 cpl_propertylist_update_double(qheader,
"CD2_2", 1.0);
3218 cpl_propertylist_update_string(qheader,
"CTYPE1",
"LINEAR");
3219 cpl_propertylist_update_string(qheader,
"CTYPE2",
"PIXEL");
3229 "Product category", instrume))
3230 fors_pmos_science_exit(
"Cannot write product category to "
3231 "QC log file", nscience);
3234 "DPR type", instrume))
3235 fors_pmos_science_exit(
"Missing keyword DPR TYPE in "
3236 "scientific frame header", nscience);
3239 "Template", instrume))
3240 fors_pmos_science_exit(
"Missing keyword TPL ID in "
3241 "scientific frame header", nscience);
3244 "Grism name", instrume))
3245 fors_pmos_science_exit(
"Missing keyword INS GRIS1 NAME in "
3246 "scientific frame header", nscience);
3249 "Grism identifier", instrume))
3250 fors_pmos_science_exit(
"Missing keyword INS GRIS1 ID in "
3251 "scientific frame header", nscience);
3253 if (cpl_propertylist_has(qheader,
"ESO INS FILT1 NAME"))
3255 "Filter name", instrume);
3258 "Collimator name", instrume))
3259 fors_pmos_science_exit(
"Missing keyword INS COLL NAME in "
3260 "scientific frame header", nscience);
3263 "Chip identifier", instrume))
3264 fors_pmos_science_exit(
"Missing keyword DET CHIP1 ID in "
3265 "scientific frame header", nscience);
3268 "Archive name of input data",
3270 fors_pmos_science_exit(
"Missing keyword ARCFILE in "
3271 "scientific frame header", nscience);
3273 pipefile = dfs_generate_filename(reduced_nul_u_tag);
3275 "Pipeline product name", instrume))
3276 fors_pmos_science_exit(
"Cannot write PIPEFILE to "
3277 "QC log file", nscience);
3278 cpl_free(pipefile); pipefile = NULL;
3285 keyname =
"QC.NULL.U.MEAN";
3289 "Mean U null parameter",
3291 fors_pmos_science_exit(
"Cannot write mean U null "
3292 "parameter to QC log file", nscience);
3295 keyname =
"QC.NANGLES";
3297 if (fors_qc_write_qc_int(qheader, nscience / 2,
3299 "Number of processed plate angles",
3301 fors_pmos_science_exit(
"Cannot write number of processed "
3302 "plate angles.", nscience);
3308 if (
dfs_save_image(frameset, punull_im, reduced_nul_u_tag, qheader,
3309 parlist, recipe, version))
3310 fors_pmos_science_exit(NULL, nscience);
3312 cpl_propertylist_delete(qheader);
3315 if (
dfs_save_image(frameset, pqerr_im, reduced_error_q_tag, header,
3316 parlist, recipe, version))
3317 fors_pmos_science_exit(NULL, nscience);
3319 if (
dfs_save_image(frameset, puerr_im, reduced_error_u_tag, header,
3320 parlist, recipe, version))
3321 fors_pmos_science_exit(NULL, nscience);
3323 if (
dfs_save_image(frameset, plerr_im, reduced_error_l_tag, header,
3324 parlist, recipe, version))
3325 fors_pmos_science_exit(NULL, nscience);
3328 parlist, recipe, version))
3329 fors_pmos_science_exit(NULL, nscience);
3331 if (
dfs_save_image(frameset, pangerr_im, reduced_error_angle_tag,
3332 header, parlist, recipe, version))
3333 fors_pmos_science_exit(NULL, nscience);
3336 header, parlist, recipe, version))
3337 fors_pmos_science_exit(NULL, nscience);
3339 cpl_image_power(pierr_im, 0.5);
3342 header, parlist, recipe, version))
3343 fors_pmos_science_exit(NULL, nscience);
3347 cpl_image_delete(pq_im);
3348 cpl_image_delete(pu_im);
3349 cpl_image_delete(pl_im);
3350 cpl_image_delete(pi_im);
3352 cpl_image_delete(pqnull_im);
3353 cpl_image_delete(punull_im);
3355 cpl_image_delete(pqerr_im);
3356 cpl_image_delete(puerr_im);
3357 cpl_image_delete(plerr_im);
3358 cpl_image_delete(pierr_im);
3359 cpl_image_delete(pang_im);
3360 cpl_image_delete(pangerr_im);
3363 cpl_propertylist_delete(header);
3367 for (j = 0; j < nscience; j++) {
3368 cpl_image_delete(reduceds[j]);
3369 cpl_image_delete(rerrors[j]);
3370 cpl_table_delete(slitss[j]);
3371 cpl_image_delete(mappeds[j]);
3379 cpl_free(instrume); instrume = NULL;
3381 cpl_free(skylocalmaps);
3383 cpl_free(nobjs_per_slit);
3385 if (cpl_error_get_code()) {
3386 cpl_msg_error(cpl_error_get_where(),
"%s", cpl_error_get_message());
3387 fors_pmos_science_exit(NULL, nscience);
3405 static float * fors_check_angles(cpl_frameset * frameset,
3406 int pmos,
const char *tag,
int * circ)
3408 float *angles = NULL;
3409 cpl_frame *c_frame = NULL;
3410 char *ret_id = NULL;
3414 angles = cpl_malloc(
sizeof(
float) * pmos);
3416 for (c_frame = cpl_frameset_find(frameset, tag);
3417 c_frame != NULL; c_frame = cpl_frameset_find(frameset, NULL)) {
3419 cpl_propertylist * header =
3420 cpl_propertylist_load(cpl_frame_get_filename(c_frame), 0);
3423 ret_id = cpl_strdup(cpl_propertylist_get_string(header,
3424 "ESO INS OPTI4 ID"));
3426 if (ret_id[1] !=
'5' && ret_id[1] !=
'4') {
3427 cpl_msg_error(cpl_func,
3428 "Unknown retarder plate id: %s", ret_id);
3432 char * c_ret_id = (
char *)
3433 cpl_propertylist_get_string(header,
"ESO INS OPTI4 ID");
3434 if (ret_id[1] != c_ret_id[1]) {
3435 cpl_msg_error(cpl_func,
"Input frames are not from the same "
3441 if (ret_id[1] ==
'5') {
3442 if (cpl_propertylist_has(header,
"ESO INS RETA2 ROT")) {
3443 angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3444 "ESO INS RETA2 ROT") + 0.5)/2;
3446 else if (cpl_propertylist_has(header,
"ESO INS RETA2 POSANG")) {
3447 if (cpl_propertylist_has(header,
"ESO ADA POSANG")) {
3448 double reta2pos = cpl_propertylist_get_double(header,
3449 "ESO INS RETA2 POSANG");
3450 double adapos = cpl_propertylist_get_double(header,
3452 angles[i] = (float)floor(2*(reta2pos - adapos) + 0.5)/2;
3455 cpl_msg_error(cpl_func,
3456 "ESO ADA POSANG not found in header");
3461 cpl_msg_error(cpl_func,
"Neither ESO INS RETA2 ROT nor "
3462 "ESO INS RETA2 POSANG found in header");
3467 if (cpl_propertylist_has(header,
"ESO INS RETA4 ROT")) {
3468 angles[i] = (float)floor(2*cpl_propertylist_get_double(header,
3469 "ESO INS RETA4 ROT") + 0.5)/2;
3472 angles[i] = angles[i] + 360;
3474 else if (cpl_propertylist_has(header,
"ESO INS RETA4 POSANG")) {
3475 if (cpl_propertylist_has(header,
"ESO ADA POSANG")) {
3476 double reta4pos = cpl_propertylist_get_double(header,
3477 "ESO INS RETA4 POSANG");
3478 double adapos = cpl_propertylist_get_double(header,
3480 angles[i] = (float)floor(2*(reta4pos - adapos) + 0.5/2);
3483 cpl_msg_error(cpl_func,
3484 "ESO ADA POSANG not found in header");
3489 cpl_msg_error(cpl_func,
"Neither ESO INS RETA4 ROT nor "
3490 "ESO INS RETA4 POSANG found in header");
3496 cpl_propertylist_delete(header);
3503 if (pmos != 2 && pmos != 4) {
3504 cpl_msg_error(cpl_func,
"Wrong angle configuration: %d angles "
3505 "found, but either 2 or 4 are required for "
3506 "circular polarization measurements!", pmos);
3510 if (pmos != 4 && pmos != 8 && pmos != 16) {
3511 cpl_msg_error(cpl_func,
"Wrong angle configuration: %d angles "
3512 "found, but either 4, 8, or 16 are required for "
3513 "linear polarization measurements!", pmos);
3521 for (i = 0; i < pmos; i++) {
3522 if (fors_find_angle_pos(angles, pmos, 90.0 * i - 45.0) < 0) {
3523 const char *cangles;
3525 case 2: cangles =
"-45.0, 45.0";
break;
3526 case 4: cangles =
"-45.0, 45.0, 135.0, 225.0";
break;
3530 cpl_msg_error(cpl_func,
"Wrong angle configuration: missing "
3531 "angle %.2f. All angles %s must be provided.",
3532 angles[i], cangles);
3538 for (i = 0; i < pmos; i++) {
3539 if (fors_find_angle_pos(angles, pmos, 22.5 * i) < 0) {
3540 const char *cangles;
3542 case 4: cangles =
"0.0, 22.5, 45.0, 67.5";
break;
3543 case 8: cangles =
"0.0, 22.5, 45.0, 67.5, "
3544 "90.0, 112.5, 135.0, 157.5";
break;
3545 case 16: cangles =
"0.0, 22.5, 45.0, 67.5, "
3546 "90.0, 112.5, 135.0, 157.5, "
3547 "180.0, 202.5, 225.0, 247.5, "
3548 "270.0, 292.5, 315.0, 337.5";
break;
3552 cpl_msg_error(cpl_func,
"Wrong angle configuration: missing "
3553 "angle %.2f. All angles %s must be provided.",
3554 angles[i], cangles);
3573 fors_find_angle_pos(
float * angles,
int nangles,
float angle)
3577 for (i = 0; i < nangles; i++) {
3578 if (fabs(angles[i] - angle) < 1.0 ||
3579 fabs(angles[i] - 360.0 - angle) < 1.0) {
3585 return match ? i : -1;
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.
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.
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
cpl_image * dfs_load_image(cpl_frameset *frameset, const char *category, cpl_type type, int ext, int calib)
Loading image data of given category.
const char * dfs_get_parameter_string(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe string parameter value.
double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines, double wavestart, double dispersion, int radius, int highres)
Estimate the spectral distortion modeling goodness.
cpl_propertylist * dfs_load_header(cpl_frameset *frameset, const char *category, int ext)
Loading header associated to data of given category.
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.
cpl_error_code dfs_save_image_ext(cpl_image *image, const char *tag, cpl_propertylist *extheader)
Save an image in a extension.
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.
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.
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.
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.
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.
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.
cpl_error_code fors_qc_start_group(cpl_propertylist *header, const char *qcdic_version, const char *instrument)
Initiate a new QC1 group.
cpl_image * mos_remove_bias(cpl_image *image, cpl_image *bias, cpl_table *overscans)
Subtract the bias from a CCD exposure.
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.
cpl_image * mos_detect_objects(cpl_image *image, cpl_table *slits, int margin, int maxradius, int conradius)
Detect objects in rectified scientific frame.
cpl_image * mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
Local determination of sky.
void fors_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
int dfs_get_parameter_bool(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe boolean parameter value.
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
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.
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)
cpl_error_code mos_object_intersect(cpl_table **slitss, cpl_table *origslits, int nscience, float tolerance)
Intersect a number of slit tables.
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.
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.
int dfs_save_image(cpl_frameset *frameset, const cpl_image *image, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const char *version)
Saving image data of given category.
cpl_table * dfs_load_table(cpl_frameset *frameset, const char *category, int ext)
Loading table data of given category.
int dfs_get_parameter_int(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe integer parameter value.
int dfs_save_table(cpl_frameset *frameset, const cpl_table *table, const char *category, cpl_propertylist *header, const cpl_parameterlist *parlist, const char *recipename, const char *version)
Saving table data of given category.
cpl_error_code fors_qc_end_group(void)
Close current QC1 PAF file.
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.
cpl_error_code mos_clean_cosmics(cpl_image *image, float gain, float threshold, float ratio)
Remove cosmic rays from sky-subtracted CCD spectral exposure.
cpl_error_code mos_randomise_image(cpl_image *image, double ron, double gain, double bias)
Randomise image.
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.