37 #include <fors_tools.h>
39 #include <fors_utils.h>
40 #include "fors_preprocess.h"
41 #include "fors_subtract_bias.h"
43 static int fors_science_create(cpl_plugin *);
44 static int fors_science_exec(cpl_plugin *);
45 static int fors_science_destroy(cpl_plugin *);
46 static int fors_science(cpl_parameterlist *, cpl_frameset *);
49 static char fors_science_description[] =
50 "This recipe is used to reduce scientific spectra using the extraction\n"
51 "mask and the products created by the recipe fors_calib. The spectra are\n"
52 "bias subtracted, flat fielded (if a normalised flat field is specified)\n"
53 "and remapped eliminating the optical distortions. The wavelength calibration\n"
54 "can be optionally upgraded using a number of sky lines: if no sky lines\n"
55 "catalog of wavelengths is specified, an internal one is used instead.\n"
56 "If the alignment to the sky lines is performed, the input dispersion\n"
57 "coefficients table is upgraded and saved to disk, and a new CCD wavelengths\n"
59 "This recipe accepts both FORS1 and FORS2 frames. A grism table (typically\n"
60 "depending on the instrument mode, and in particular on the grism used)\n"
61 "may also be specified: this table contains a default recipe parameter\n"
62 "setting to control the way spectra are extracted for a specific instrument\n"
63 "mode, as it is used for automatic run of the pipeline on Paranal and in\n"
64 "Garching. If this table is specified, it will modify the default recipe\n"
65 "parameter setting, with the exception of those parameters which have been\n"
66 "explicitly modifyed on the command line. If a grism table is not specified,\n"
67 "the input recipe parameters values will always be read from the command\n"
68 "line, or from an esorex configuration file if present, or from their\n"
69 "generic default values (that are rarely meaningful).\n"
70 "In the table below the MXU acronym can be read alternatively as MOS\n"
71 "and LSS, depending on the instrument mode of the input data. The acronym\n"
72 "SCI on products should be read STD in case of standard stars observations\n"
73 "A CURV_COEFF table is not (yet) expected for LSS data.\n"
74 "Either a scientific or a standard star exposure can be specified in input.\n"
75 "Only in case of a standard star exposure input, the atmospheric extinction\n"
76 "table and a table with the physical fluxes of the observed standard star\n"
77 "must be specified in input, and a spectro-photometric table is created in\n"
78 "output. This table can then be input again to this recipe, always with an\n"
79 "atmospheric extinction table, and if a photometric calibration is requested\n"
80 "then flux calibrated spectra (in units of erg/cm/cm/s/Angstrom) are also\n"
81 "written in output.\n\n"
84 " DO category: Type: Explanation: Required:\n"
85 " SCIENCE_MXU Raw Scientific exposure Y\n"
86 " or STANDARD_MXU Raw Standard star exposure Y\n"
87 " MASTER_BIAS Calib Master bias Y\n"
88 " GRISM_TABLE Calib Grism table .\n"
89 " MASTER_SKYLINECAT Calib Sky lines catalog .\n"
91 " MASTER_NORM_FLAT_MXU Calib Normalised flat field .\n"
92 " DISP_COEFF_MXU Calib Inverse dispersion Y\n"
93 " CURV_COEFF_MXU Calib Spectral curvature Y\n"
94 " SLIT_LOCATION_MXU Calib Slits positions table Y\n"
96 " or, in case of LSS-like MOS/MXU data,\n"
98 " MASTER_NORM_FLAT_LONG_MXU Calib Normalised flat field .\n"
99 " DISP_COEFF_LONG_MXU Calib Inverse dispersion Y\n"
101 " In case STANDARD_MXU is specified in input,\n"
103 " EXTINCT_TABLE Calib Atmospheric extinction Y\n"
104 " STD_FLUX_TABLE Calib Standard star flux Y\n"
106 " The following input files are mandatory if photometric calibrated"
107 " spectra are desired:\n"
109 " EXTINCT_TABLE Calib Atmospheric extinction Y\n"
110 " SPECPHOT_TABLE Calib Response curves Y\n"
112 " If requested for standard star data, the SPECPHOT_TABLE can be dropped:\n"
113 " in this case the correction is applied using the SPECPHOT_TABLE produced\n"
114 " in the same run.\n"
118 " DO category: Data type: Explanation:\n"
119 " REDUCED_SCI_MXU FITS image Extracted scientific spectra\n"
120 " REDUCED_SKY_SCI_MXU FITS image Extracted sky spectra\n"
121 " REDUCED_ERROR_SCI_MXU FITS image Errors on extracted spectra\n"
122 " UNMAPPED_SCI_MXU FITS image Sky subtracted scientific spectra\n"
123 " MAPPED_SCI_MXU FITS image Rectified scientific spectra\n"
124 " MAPPED_ALL_SCI_MXU FITS image Rectified science spectra with sky\n"
125 " MAPPED_SKY_SCI_MXU FITS image Rectified sky spectra\n"
126 " UNMAPPED_SKY_SCI_MXU FITS image Sky on CCD\n"
127 " OBJECT_TABLE_SCI_MXU FITS table Positions of detected objects\n"
129 " Only if the global sky subtraction is requested:\n"
130 " GLOBAL_SKY_SPECTRUM_MXU FITS table Global sky spectrum\n"
132 " Only if the sky-alignment of the wavelength solution is requested:\n"
133 " SKY_SHIFTS_LONG_SCI_MXU FITS table Sky lines offsets (LSS-like data)\n"
134 " or SKY_SHIFTS_SLIT_SCI_MXU FITS table Sky lines offsets (MOS-like data)\n"
135 " DISP_COEFF_SCI_MXU FITS table Upgraded dispersion coefficients\n"
136 " WAVELENGTH_MAP_SCI_MXU FITS image Upgraded wavelength map\n"
138 " Only if a STANDARD_MXU is specified in input:\n"
139 " SPECPHOT_TABLE FITS table Efficiency and response curves\n"
141 " Only if a photometric calibration was requested:\n"
142 " REDUCED_FLUX_SCI_MXU FITS image Flux calibrated scientific spectra\n"
143 " REDUCED_FLUX_ERROR_SCI_MXU FITS image Errors on flux calibrated spectra\n"
144 " MAPPED_FLUX_SCI_MXU FITS image Flux calibrated slit spectra\n\n";
146 #define fors_science_exit(message) \
148 if (message) cpl_msg_error(recipe, message); \
150 cpl_free(instrume); \
151 cpl_image_delete(dummy); \
152 cpl_image_delete(mapped); \
153 cpl_image_delete(mapped_sky); \
154 cpl_image_delete(mapped_cleaned); \
155 cpl_image_delete(skylocalmap); \
156 cpl_image_delete(skymap); \
157 cpl_image_delete(smapped); \
158 cpl_table_delete(offsets); \
159 cpl_table_delete(photcal); \
160 cpl_table_delete(sky); \
161 fors_image_delete(&bias); \
162 cpl_image_delete(spectra); \
163 cpl_image_delete(coordinate); \
164 fors_image_delete(&norm_flat); \
165 cpl_image_delete(rainbow); \
166 cpl_image_delete(rectified); \
167 cpl_image_delete(wavemap); \
168 cpl_image_delete(wavemaplss); \
169 cpl_propertylist_delete(qclist); \
170 cpl_propertylist_delete(header); \
171 cpl_propertylist_delete(save_header); \
172 cpl_table_delete(grism_table); \
173 cpl_table_delete(idscoeff); \
174 cpl_table_delete(maskslits); \
175 cpl_table_delete(overscans); \
176 cpl_table_delete(polytraces); \
177 cpl_table_delete(slits); \
178 cpl_table_delete(wavelengths); \
179 cpl_vector_delete(lines); \
180 cpl_msg_indent_less(); \
185 #define fors_science_exit_memcheck(message) \
187 if (message) cpl_msg_info(recipe, message); \
189 cpl_free(instrume); \
190 cpl_image_delete(dummy); \
191 cpl_image_delete(mapped); \
192 cpl_image_delete(mapped_cleaned); \
193 cpl_image_delete(mapped_sky); \
194 cpl_image_delete(skylocalmap); \
195 cpl_image_delete(skymap); \
196 cpl_image_delete(smapped); \
197 cpl_table_delete(offsets); \
198 cpl_table_delete(photcal); \
199 cpl_table_delete(sky); \
200 fors_image_delete(&bias); \
201 cpl_image_delete(spectra); \
202 cpl_image_delete(coordinate); \
203 fors_image_delete(&norm_flat); \
204 cpl_image_delete(rainbow); \
205 cpl_image_delete(rectified); \
206 cpl_image_delete(wavemap); \
207 cpl_image_delete(wavemaplss); \
208 cpl_propertylist_delete(header); \
209 cpl_propertylist_delete(save_header); \
210 cpl_table_delete(grism_table); \
211 cpl_table_delete(idscoeff); \
212 cpl_table_delete(maskslits); \
213 cpl_table_delete(overscans); \
214 cpl_table_delete(polytraces); \
215 cpl_table_delete(slits); \
216 cpl_table_delete(wavelengths); \
217 cpl_vector_delete(lines); \
218 cpl_msg_indent_less(); \
236 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
237 cpl_plugin *plugin = &recipe->interface;
239 cpl_plugin_init(plugin,
242 CPL_PLUGIN_TYPE_RECIPE,
244 "Extraction of scientific spectra",
245 fors_science_description,
251 fors_science_destroy);
253 cpl_pluginlist_append(list, plugin);
269 static int fors_science_create(cpl_plugin *plugin)
279 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
280 recipe = (cpl_recipe *)plugin;
288 recipe->parameters = cpl_parameterlist_new();
295 p = cpl_parameter_new_value(
"fors.fors_science.dispersion",
297 "Resampling step (Angstrom/pixel)",
300 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dispersion");
301 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
302 cpl_parameterlist_append(recipe->parameters, p);
308 p = cpl_parameter_new_value(
"fors.fors_science.skyalign",
310 "Polynomial order for sky lines alignment, "
311 "or -1 to avoid alignment",
314 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"skyalign");
315 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
316 cpl_parameterlist_append(recipe->parameters, p);
322 p = cpl_parameter_new_value(
"fors.fors_science.wcolumn",
324 "Name of sky line catalog table column "
328 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wcolumn");
329 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
330 cpl_parameterlist_append(recipe->parameters, p);
336 p = cpl_parameter_new_value(
"fors.fors_science.startwavelength",
338 "Start wavelength in spectral extraction",
341 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"startwavelength");
342 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
343 cpl_parameterlist_append(recipe->parameters, p);
349 p = cpl_parameter_new_value(
"fors.fors_science.endwavelength",
351 "End wavelength in spectral extraction",
354 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"endwavelength");
355 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
356 cpl_parameterlist_append(recipe->parameters, p);
362 p = cpl_parameter_new_value(
"fors.fors_science.flatfield",
367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"flatfield");
368 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
369 cpl_parameterlist_append(recipe->parameters, p);
375 p = cpl_parameter_new_value(
"fors.fors_science.skyglobal",
377 "Subtract global sky spectrum from CCD",
380 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"skyglobal");
381 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
382 cpl_parameterlist_append(recipe->parameters, p);
401 p = cpl_parameter_new_value(
"fors.fors_science.skymedian",
403 "Sky subtraction from extracted slit spectra",
406 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"skymedian");
407 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
408 cpl_parameterlist_append(recipe->parameters, p);
414 p = cpl_parameter_new_value(
"fors.fors_science.skylocal",
416 "Sky subtraction from CCD slit spectra",
419 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"skylocal");
420 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
421 cpl_parameterlist_append(recipe->parameters, p);
427 p = cpl_parameter_new_value(
"fors.fors_science.cosmics",
429 "Eliminate cosmic rays hits (only if global "
430 "sky subtraction is also requested)",
433 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cosmics");
434 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
435 cpl_parameterlist_append(recipe->parameters, p);
441 p = cpl_parameter_new_value(
"fors.fors_science.slit_margin",
443 "Number of pixels to exclude at each slit "
444 "in object detection and extraction",
447 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"slit_margin");
448 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
449 cpl_parameterlist_append(recipe->parameters, p);
455 p = cpl_parameter_new_value(
"fors.fors_science.ext_radius",
457 "Maximum extraction radius for detected "
461 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ext_radius");
462 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
463 cpl_parameterlist_append(recipe->parameters, p);
469 p = cpl_parameter_new_value(
"fors.fors_science.cont_radius",
471 "Minimum distance at which two objects "
472 "of equal luminosity do not contaminate "
473 "each other (pixel)",
476 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cont_radius");
477 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
478 cpl_parameterlist_append(recipe->parameters, p);
484 p = cpl_parameter_new_value(
"fors.fors_science.ext_mode",
486 "Object extraction method: 0 = aperture, "
487 "1 = Horne optimal extraction",
490 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ext_mode");
491 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
492 cpl_parameterlist_append(recipe->parameters, p);
498 p = cpl_parameter_new_value(
"fors.fors_science.response",
500 "Order of polynomial modeling the "
501 "instrument response",
504 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"response");
505 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
506 cpl_parameterlist_append(recipe->parameters, p);
520 static int fors_science_exec(cpl_plugin *plugin)
524 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
525 recipe = (cpl_recipe *)plugin;
529 return fors_science(recipe->parameters, recipe->frames);
541 static int fors_science_destroy(cpl_plugin *plugin)
545 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
546 recipe = (cpl_recipe *)plugin;
550 cpl_parameterlist_delete(recipe->parameters);
565 static int fors_science(cpl_parameterlist *parlist, cpl_frameset *frameset)
568 const char *recipe =
"fors_science";
578 double startwavelength;
579 double endwavelength;
597 fors_image_list *all_science;
603 cpl_image *spectra = NULL;
604 cpl_image *rectified = NULL;
605 cpl_image *coordinate = NULL;
606 cpl_image *rainbow = NULL;
607 cpl_image *mapped = NULL;
608 cpl_image *mapped_sky = NULL;
609 cpl_image *mapped_cleaned = NULL;
610 cpl_image *smapped = NULL;
611 cpl_image *wavemap = NULL;
612 cpl_image *wavemaplss = NULL;
613 cpl_image *skymap = NULL;
614 cpl_image *skylocalmap = NULL;
615 cpl_image *dummy = NULL;
617 cpl_table *grism_table = NULL;
618 cpl_table *overscans = NULL;
619 cpl_table *wavelengths = NULL;
620 cpl_table *idscoeff = NULL;
621 cpl_table *slits = NULL;
622 cpl_table *maskslits = NULL;
623 cpl_table *polytraces = NULL;
624 cpl_table *offsets = NULL;
625 cpl_table *sky = NULL;
626 cpl_table *photcal = NULL;
628 cpl_vector *lines = NULL;
630 cpl_propertylist *header = NULL;
631 cpl_propertylist *save_header = NULL;
632 cpl_propertylist *qclist = NULL;
640 char *instrume = NULL;
642 const char *science_tag = NULL;
643 const char *master_norm_flat_tag = NULL;
644 const char *disp_coeff_tag = NULL;
645 const char *disp_coeff_sky_tag = NULL;
646 const char *wavelength_map_sky_tag = NULL;
647 const char *curv_coeff_tag = NULL;
648 const char *slit_location_tag = NULL;
649 const char *reduced_science_tag = NULL;
650 const char *reduced_flux_science_tag = NULL;
651 const char *reduced_sky_tag = NULL;
652 const char *reduced_error_tag = NULL;
653 const char *reduced_flux_error_tag = NULL;
654 const char *mapped_science_tag = NULL;
655 const char *mapped_flux_science_tag = NULL;
656 const char *unmapped_science_tag = NULL;
657 const char *mapped_science_sky_tag = NULL;
658 const char *mapped_sky_tag = NULL;
659 const char *unmapped_sky_tag = NULL;
660 const char *global_sky_spectrum_tag = NULL;
661 const char *object_table_tag = NULL;
662 const char *skylines_offsets_tag = NULL;
663 const char *specphot_tag;
664 const char *master_specphot_tag =
"MASTER_SPECPHOT_TABLE";
666 int treat_as_lss = 0;
669 double *exptime = NULL;
678 int ccd_xsize, ccd_ysize;
690 snprintf(version, 80,
"%s-%s", PACKAGE, PACKAGE_VERSION);
692 cpl_msg_set_indentation(2);
699 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
700 cpl_msg_indent_more();
702 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
703 fors_science_exit(
"Too many in input: GRISM_TABLE");
708 "fors.fors_science.dispersion", grism_table);
710 if (dispersion <= 0.0)
711 fors_science_exit(
"Invalid resampling step");
714 "fors.fors_science.skyalign", NULL);
717 fors_science_exit(
"Max polynomial degree for sky alignment is 2");
720 "fors.fors_science.wcolumn", NULL);
723 "fors.fors_science.startwavelength", grism_table);
724 if (startwavelength < 3000.0 || startwavelength > 13000.0)
725 fors_science_exit(
"Invalid wavelength");
728 "fors.fors_science.endwavelength", grism_table);
729 if (endwavelength < 3000.0 || endwavelength > 13000.0)
730 fors_science_exit(
"Invalid wavelength");
732 if (endwavelength - startwavelength <= 0.0)
733 fors_science_exit(
"Invalid wavelength interval");
749 if (skylocal && skyglobal)
750 fors_science_exit(
"Cannot apply both local and global sky subtraction");
752 if (skylocal && skymedian)
753 fors_science_exit(
"Cannot apply sky subtraction both on extracted "
754 "and non-extracted spectra");
757 "fors.fors_science.cosmics", NULL);
760 if (!(skyglobal || skylocal))
761 fors_science_exit(
"Cosmic rays correction requires "
762 "either skylocal=true or skyglobal=true");
765 "fors.fors_science.slit_margin",
768 fors_science_exit(
"Value must be zero or positive");
773 fors_science_exit(
"Value must be zero or positive");
776 "fors.fors_science.cont_radius",
779 fors_science_exit(
"Value must be zero or positive");
783 if (ext_mode < 0 || ext_mode > 1)
784 fors_science_exit(
"Invalid object extraction mode");
788 if (res_order < 2 || res_order > 10)
789 fors_science_exit(
"Invalid instrument response modeling polynomial");
791 cpl_table_delete(grism_table); grism_table = NULL;
793 if (cpl_error_get_code())
794 fors_science_exit(
"Failure getting the configuration parameters");
801 cpl_msg_indent_less();
802 cpl_msg_info(recipe,
"Check input set-of-frames:");
803 cpl_msg_indent_more();
805 mxu = cpl_frameset_count_tags(frameset,
"SCIENCE_MXU");
806 mos = cpl_frameset_count_tags(frameset,
"SCIENCE_MOS");
807 lss = cpl_frameset_count_tags(frameset,
"SCIENCE_LSS");
810 if (mxu + mos + lss == 0) {
811 mxu = cpl_frameset_count_tags(frameset,
"STANDARD_MXU");
812 mos = cpl_frameset_count_tags(frameset,
"STANDARD_MOS");
813 lss = cpl_frameset_count_tags(frameset,
"STANDARD_LSS");
817 if (mxu + mos + lss == 0)
818 fors_science_exit(
"Missing input scientific frame");
820 nscience = mxu + mos + lss;
822 if (mxu && mxu < nscience)
823 fors_science_exit(
"Input scientific frames must be of the same type");
825 if (mos && mos < nscience)
826 fors_science_exit(
"Input scientific frames must be of the same type");
828 if (lss && lss < nscience)
829 fors_science_exit(
"Input scientific frames must be of the same type");
832 cpl_msg_info(recipe,
"MXU data found");
834 science_tag =
"STANDARD_MXU";
835 reduced_science_tag =
"REDUCED_STD_MXU";
836 reduced_flux_science_tag =
"REDUCED_FLUX_STD_MXU";
837 unmapped_science_tag =
"UNMAPPED_STD_MXU";
838 mapped_science_tag =
"MAPPED_STD_MXU";
839 mapped_flux_science_tag =
"MAPPED_FLUX_STD_MXU";
840 mapped_science_sky_tag =
"MAPPED_ALL_STD_MXU";
841 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_STD_MXU";
842 wavelength_map_sky_tag =
"WAVELENGTH_MAP_STD_MXU";
843 disp_coeff_sky_tag =
"DISP_COEFF_STD_MXU";
844 mapped_sky_tag =
"MAPPED_SKY_STD_MXU";
845 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MXU";
846 object_table_tag =
"OBJECT_TABLE_STD_MXU";
847 reduced_sky_tag =
"REDUCED_SKY_STD_MXU";
848 reduced_error_tag =
"REDUCED_ERROR_STD_MXU";
849 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_STD_MXU";
850 specphot_tag =
"SPECPHOT_TABLE";
853 science_tag =
"SCIENCE_MXU";
854 reduced_science_tag =
"REDUCED_SCI_MXU";
855 reduced_flux_science_tag =
"REDUCED_FLUX_SCI_MXU";
856 unmapped_science_tag =
"UNMAPPED_SCI_MXU";
857 mapped_science_tag =
"MAPPED_SCI_MXU";
858 mapped_flux_science_tag =
"MAPPED_FLUX_SCI_MXU";
859 mapped_science_sky_tag =
"MAPPED_ALL_SCI_MXU";
860 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_SCI_MXU";
861 wavelength_map_sky_tag =
"WAVELENGTH_MAP_SCI_MXU";
862 disp_coeff_sky_tag =
"DISP_COEFF_SCI_MXU";
863 mapped_sky_tag =
"MAPPED_SKY_SCI_MXU";
864 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MXU";
865 object_table_tag =
"OBJECT_TABLE_SCI_MXU";
866 reduced_sky_tag =
"REDUCED_SKY_SCI_MXU";
867 reduced_error_tag =
"REDUCED_ERROR_SCI_MXU";
868 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_SCI_MXU";
869 specphot_tag =
"SPECPHOT_TABLE";
872 master_norm_flat_tag =
"MASTER_NORM_FLAT_MXU";
873 disp_coeff_tag =
"DISP_COEFF_MXU";
874 curv_coeff_tag =
"CURV_COEFF_MXU";
875 slit_location_tag =
"SLIT_LOCATION_MXU";
876 global_sky_spectrum_tag =
"GLOBAL_SKY_SPECTRUM_MXU";
878 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
879 master_norm_flat_tag =
"MASTER_NORM_FLAT_LONG_MXU";
880 disp_coeff_tag =
"DISP_COEFF_LONG_MXU";
881 slit_location_tag =
"SLIT_LOCATION_LONG_MXU";
886 cpl_msg_info(recipe,
"LSS data found");
888 if (cosmics && !skyglobal)
889 fors_science_exit(
"Cosmic rays correction for LSS "
890 "data requires --skyglobal=true");
893 science_tag =
"STANDARD_LSS";
894 reduced_science_tag =
"REDUCED_STD_LSS";
895 reduced_flux_science_tag =
"REDUCED_FLUX_STD_LSS";
896 unmapped_science_tag =
"UNMAPPED_STD_LSS";
897 mapped_science_tag =
"MAPPED_STD_LSS";
898 mapped_flux_science_tag =
"MAPPED_FLUX_STD_LSS";
899 mapped_science_sky_tag =
"MAPPED_ALL_STD_LSS";
900 skylines_offsets_tag =
"SKY_SHIFTS_LONG_STD_LSS";
901 wavelength_map_sky_tag =
"WAVELENGTH_MAP_STD_LSS";
902 disp_coeff_sky_tag =
"DISP_COEFF_STD_LSS";
903 mapped_sky_tag =
"MAPPED_SKY_STD_LSS";
904 unmapped_sky_tag =
"UNMAPPED_SKY_STD_LSS";
905 object_table_tag =
"OBJECT_TABLE_STD_LSS";
906 reduced_sky_tag =
"REDUCED_SKY_STD_LSS";
907 reduced_error_tag =
"REDUCED_ERROR_STD_LSS";
908 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_STD_LSS";
909 specphot_tag =
"SPECPHOT_TABLE";
912 science_tag =
"SCIENCE_LSS";
913 reduced_science_tag =
"REDUCED_SCI_LSS";
914 reduced_flux_science_tag =
"REDUCED_FLUX_SCI_LSS";
915 unmapped_science_tag =
"UNMAPPED_SCI_LSS";
916 mapped_science_tag =
"MAPPED_SCI_LSS";
917 mapped_flux_science_tag =
"MAPPED_FLUX_SCI_LSS";
918 mapped_science_sky_tag =
"MAPPED_ALL_SCI_LSS";
919 skylines_offsets_tag =
"SKY_SHIFTS_LONG_SCI_LSS";
920 wavelength_map_sky_tag =
"WAVELENGTH_MAP_SCI_LSS";
921 disp_coeff_sky_tag =
"DISP_COEFF_SCI_LSS";
922 mapped_sky_tag =
"MAPPED_SKY_SCI_LSS";
923 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_LSS";
924 object_table_tag =
"OBJECT_TABLE_SCI_LSS";
925 reduced_sky_tag =
"REDUCED_SKY_SCI_LSS";
926 reduced_error_tag =
"REDUCED_ERROR_SCI_LSS";
927 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_SCI_LSS";
928 specphot_tag =
"SPECPHOT_TABLE";
931 master_norm_flat_tag =
"MASTER_NORM_FLAT_LSS";
932 disp_coeff_tag =
"DISP_COEFF_LSS";
933 slit_location_tag =
"SLIT_LOCATION_LSS";
934 global_sky_spectrum_tag =
"GLOBAL_SKY_SPECTRUM_LSS";
938 cpl_msg_info(recipe,
"MOS data found");
940 science_tag =
"STANDARD_MOS";
941 reduced_science_tag =
"REDUCED_STD_MOS";
942 reduced_flux_science_tag =
"REDUCED_FLUX_STD_MOS";
943 unmapped_science_tag =
"UNMAPPED_STD_MOS";
944 mapped_science_tag =
"MAPPED_STD_MOS";
945 mapped_flux_science_tag =
"MAPPED_FLUX_STD_MOS";
946 mapped_science_sky_tag =
"MAPPED_ALL_STD_MOS";
947 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_STD_MOS";
948 wavelength_map_sky_tag =
"WAVELENGTH_MAP_STD_MOS";
949 disp_coeff_sky_tag =
"DISP_COEFF_STD_MOS";
950 mapped_sky_tag =
"MAPPED_SKY_STD_MOS";
951 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MOS";
952 object_table_tag =
"OBJECT_TABLE_STD_MOS";
953 reduced_sky_tag =
"REDUCED_SKY_STD_MOS";
954 reduced_error_tag =
"REDUCED_ERROR_STD_MOS";
955 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_STD_MOS";
956 specphot_tag =
"SPECPHOT_TABLE";
959 science_tag =
"SCIENCE_MOS";
960 reduced_science_tag =
"REDUCED_SCI_MOS";
961 reduced_flux_science_tag =
"REDUCED_FLUX_SCI_MOS";
962 unmapped_science_tag =
"UNMAPPED_SCI_MOS";
963 mapped_science_tag =
"MAPPED_SCI_MOS";
964 mapped_flux_science_tag =
"MAPPED_FLUX_SCI_MOS";
965 mapped_science_sky_tag =
"MAPPED_ALL_SCI_MOS";
966 skylines_offsets_tag =
"SKY_SHIFTS_SLIT_SCI_MOS";
967 wavelength_map_sky_tag =
"WAVELENGTH_MAP_SCI_MOS";
968 disp_coeff_sky_tag =
"DISP_COEFF_SCI_MOS";
969 mapped_sky_tag =
"MAPPED_SKY_SCI_MOS";
970 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MOS";
971 object_table_tag =
"OBJECT_TABLE_SCI_MOS";
972 reduced_sky_tag =
"REDUCED_SKY_SCI_MOS";
973 reduced_error_tag =
"REDUCED_ERROR_SCI_MOS";
974 reduced_flux_error_tag =
"REDUCED_FLUX_ERROR_SCI_MOS";
975 specphot_tag =
"SPECPHOT_TABLE";
978 master_norm_flat_tag =
"MASTER_NORM_FLAT_MOS";
979 disp_coeff_tag =
"DISP_COEFF_MOS";
980 curv_coeff_tag =
"CURV_COEFF_MOS";
981 slit_location_tag =
"SLIT_LOCATION_MOS";
982 global_sky_spectrum_tag =
"GLOBAL_SKY_SPECTRUM_MOS";
984 if (!cpl_frameset_count_tags(frameset, master_norm_flat_tag)) {
985 master_norm_flat_tag =
"MASTER_NORM_FLAT_LONG_MOS";
986 disp_coeff_tag =
"DISP_COEFF_LONG_MOS";
987 slit_location_tag =
"SLIT_LOCATION_LONG_MOS";
991 if (cpl_frameset_count_tags(frameset,
"MASTER_BIAS") == 0)
992 fors_science_exit(
"Missing required input: MASTER_BIAS");
994 if (cpl_frameset_count_tags(frameset,
"MASTER_BIAS") > 1)
995 fors_science_exit(
"Too many in input: MASTER_BIAS");
998 if (cpl_frameset_count_tags(frameset,
"MASTER_SKYLINECAT") > 1)
999 fors_science_exit(
"Too many in input: MASTER_SKYLINECAT");
1001 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) == 0) {
1002 cpl_msg_error(recipe,
"Missing required input: %s", disp_coeff_tag);
1003 fors_science_exit(NULL);
1006 if (cpl_frameset_count_tags(frameset, disp_coeff_tag) > 1) {
1007 cpl_msg_error(recipe,
"Too many in input: %s", disp_coeff_tag);
1008 fors_science_exit(NULL);
1011 if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
1012 cpl_msg_error(recipe,
"Missing required input: %s",
1014 fors_science_exit(NULL);
1017 if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
1018 cpl_msg_error(recipe,
"Too many in input: %s", slit_location_tag);
1019 fors_science_exit(NULL);
1022 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) > 1) {
1024 cpl_msg_error(recipe,
"Too many in input: %s",
1025 master_norm_flat_tag);
1026 fors_science_exit(NULL);
1029 cpl_msg_warning(recipe,
"%s in input are ignored, "
1030 "since flat field correction was not requested",
1031 master_norm_flat_tag);
1035 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 1) {
1037 cpl_msg_warning(recipe,
"%s in input is ignored, "
1038 "since flat field correction was not requested",
1039 master_norm_flat_tag);
1043 if (cpl_frameset_count_tags(frameset, master_norm_flat_tag) == 0) {
1045 cpl_msg_error(recipe,
"Flat field correction was requested, "
1046 "but no %s are found in input",
1047 master_norm_flat_tag);
1048 fors_science_exit(NULL);
1054 if (cpl_frameset_count_tags(frameset,
"EXTINCT_TABLE") == 0) {
1055 cpl_msg_warning(recipe,
"An EXTINCT_TABLE was not found in input: "
1056 "instrument response curve will not be produced.");
1060 if (cpl_frameset_count_tags(frameset,
"EXTINCT_TABLE") > 1)
1061 fors_science_exit(
"Too many in input: EXTINCT_TABLE");
1063 if (cpl_frameset_count_tags(frameset,
"STD_FLUX_TABLE") == 0) {
1064 cpl_msg_warning(recipe,
"A STD_FLUX_TABLE was not found in input: "
1065 "instrument response curve will not be produced.");
1069 if (cpl_frameset_count_tags(frameset,
"STD_FLUX_TABLE") > 1)
1070 fors_science_exit(
"Too many in input: STD_FLUX_TABLE");
1073 cpl_msg_warning(recipe,
"The target name of observation does not "
1074 "match the standard star catalog: "
1075 "instrument response curve will not be produced.");
1080 have_phot = cpl_frameset_count_tags(frameset, specphot_tag);
1081 have_phot += cpl_frameset_count_tags(frameset, master_specphot_tag);
1084 if (have_phot == 0) {
1085 cpl_msg_info(recipe,
1086 "A SPECPHOT_TABLE was not found in input: "
1087 "no photometric calibrated "
1088 "spectra will be produced.");
1093 cpl_msg_info(recipe,
1094 "A SPECPHOT_TABLE was found in input: "
1095 "photometric calibrated "
1096 "spectra will be produced.");
1101 if (cpl_frameset_count_tags(frameset,
"EXTINCT_TABLE") != 1)
1102 fors_science_exit(
"One and only one EXTINCT_TABLE is needed "
1103 "to calibrate in photometry");
1107 fors_science_exit(
"Too many in input: SPECPHOT_TABLE");
1112 fors_science_exit(
"Input frames are not from the same grism");
1115 fors_science_exit(
"Input frames are not from the same filter");
1117 if (cpl_frameset_count_tags(frameset,
"SPECPHOT_TABLE"))
1119 cpl_frameset * frameset_nostd = cpl_frameset_duplicate(frameset);
1120 cpl_frameset_erase(frameset_nostd,
"SPECPHOT_TABLE");
1122 fors_science_exit(
"Input frames are not from the same chip."
1123 " This does not apply to specphot table.");
1124 cpl_frameset_delete(frameset_nostd);
1129 fors_science_exit(
"Input frames are not from the same chip");
1133 cpl_frameset * frameset_detector = cpl_frameset_duplicate(frameset);
1134 cpl_frameset_erase(frameset_detector,
"GRISM_TABLE");
1136 fors_science_exit(
"Input frames are not from the same chip mosaic");
1137 cpl_frameset_delete(frameset_detector);
1140 cpl_msg_indent_less();
1150 exptime = cpl_calloc(nscience,
sizeof(
double));
1154 cpl_msg_info(recipe,
"Load %d scientific frames and median them...",
1156 cpl_msg_indent_more();
1162 fors_science_exit(
"Cannot load scientific frame header");
1164 alltime = exptime[0] = cpl_propertylist_get_double(header,
"EXPTIME");
1166 if (cpl_error_get_code() != CPL_ERROR_NONE)
1167 fors_science_exit(
"Missing keyword EXPTIME in scientific "
1170 if (standard || photometry) {
1173 fors_science_exit(
"Missing airmass information in "
1174 "scientific frame header");
1177 cpl_propertylist_delete(header); header = NULL;
1179 cpl_msg_info(recipe,
"Scientific frame 1 exposure time: %.2f s",
1182 for (i = 1; i < nscience; i++) {
1187 fors_science_exit(
"Cannot load scientific frame header");
1189 exptime[i] = cpl_propertylist_get_double(header,
"EXPTIME");
1191 alltime += exptime[i];
1193 if (cpl_error_get_code() != CPL_ERROR_NONE)
1194 fors_science_exit(
"Missing keyword EXPTIME in scientific "
1197 cpl_propertylist_delete(header); header = NULL;
1199 cpl_msg_info(recipe,
"Scientific frame %d exposure time: %.2f s",
1203 all_science = fors_image_list_new();
1206 for (i = 0; i < nscience; i++)
1208 cpl_frame * this_science_frame =
1209 cpl_frameset_get_position(science_frames, i);
1211 fors_image_load_preprocess(this_science_frame);
1213 if (this_science_ima) {
1215 fors_image_list_insert(all_science, this_science_ima);
1218 fors_science_exit(
"Cannot load scientific frame");
1221 hdrl_image *combined;
1223 hdrl_imagelist * all_science_hdrl = fors_image_list_to_hdrl(all_science);
1224 hdrl_parameter * combine_par = hdrl_collapse_median_parameter_create();
1225 hdrl_imagelist_collapse(all_science_hdrl, combine_par,
1226 &combined, &contrib);
1228 science_ima = fors_image_from_hdrl(combined);
1231 spectra = science_ima->data;
1233 hdrl_imagelist_delete(all_science_hdrl);
1235 hdrl_image_delete(combined);
1236 hdrl_parameter_delete(combine_par);
1237 cpl_image_delete(contrib);
1238 cpl_frameset_delete(science_frames);
1241 cpl_msg_info(recipe,
"Load scientific exposure...");
1242 cpl_msg_indent_more();
1247 fors_science_exit(
"Cannot load scientific frame header");
1249 if (standard || photometry) {
1252 fors_science_exit(
"Missing airmass information in "
1253 "scientific frame header");
1260 wheel4 = (
char *)cpl_propertylist_get_string(header,
1261 "ESO INS OPTI9 TYPE");
1262 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1263 fors_science_exit(
"Missing ESO INS OPTI9 TYPE in flat header");
1266 if (strcmp(
"FILT", wheel4) == 0) {
1267 wheel4 = (
char *)cpl_propertylist_get_string(header,
1268 "ESO INS OPTI9 NAME");
1269 cpl_msg_error(recipe,
"Unsupported filter: %s", wheel4);
1270 fors_science_exit(NULL);
1273 alltime = exptime[0] = cpl_propertylist_get_double(header,
"EXPTIME");
1275 if (cpl_error_get_code() != CPL_ERROR_NONE)
1276 fors_science_exit(
"Missing keyword EXPTIME in scientific "
1279 cpl_propertylist_delete(header); header = NULL;
1281 cpl_msg_info(recipe,
"Scientific frame exposure time: %.2f s",
1284 const cpl_frame * science_frame =
1285 cpl_frameset_find_const(frameset, science_tag);
1286 science_ima = fors_image_load_preprocess(science_frame);
1287 spectra = science_ima->data;
1290 if (spectra == NULL)
1291 fors_science_exit(
"Cannot load scientific frame");
1293 cpl_free(exptime); exptime = NULL;
1295 cpl_msg_indent_less();
1306 fors_science_exit(
"Cannot load scientific frame header");
1308 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
1309 if (instrume == NULL)
1310 fors_science_exit(
"Missing keyword INSTRUME in scientific header");
1311 instrume = cpl_strdup(instrume);
1313 if (instrume[4] ==
'1')
1314 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
1315 if (instrume[4] ==
'2')
1316 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
1318 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
1320 if (cpl_error_get_code() != CPL_ERROR_NONE)
1321 fors_science_exit(
"Missing keyword ESO INS GRIS1 WLEN in scientific "
1324 if (reference < 3000.0)
1327 if (reference < 3000.0 || reference > 13000.0) {
1328 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
1329 "keyword ESO INS GRIS1 WLEN in scientific frame header",
1331 fors_science_exit(NULL);
1334 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
1336 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
1338 if (cpl_error_get_code() != CPL_ERROR_NONE)
1339 fors_science_exit(
"Missing keyword ESO DET WIN1 BINX in scientific "
1343 dispersion *= rebin;
1344 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
1345 "resampling step used is %f A/pixel", rebin,
1347 ext_radius /= rebin;
1348 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
1349 "extraction radius used is %d pixel", rebin,
1353 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
1355 if (cpl_error_get_code() != CPL_ERROR_NONE)
1356 fors_science_exit(
"Missing keyword ESO DET OUT1 CONAD in scientific "
1359 cpl_msg_info(recipe,
"The gain factor is: %.2f e-/ADU", gain);
1361 ron = cpl_propertylist_get_double(header,
"ESO DET OUT1 RON");
1363 if (cpl_error_get_code() != CPL_ERROR_NONE)
1364 fors_science_exit(
"Missing keyword ESO DET OUT1 RON in scientific "
1369 cpl_msg_info(recipe,
"The read-out-noise is: %.2f ADU", ron);
1372 int nslits_out_det = 0;
1384 mxpos = cpl_table_get_column_median(maskslits,
"xtop");
1386 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
1388 cpl_table_delete(maskslits); maskslits = NULL;
1392 cpl_msg_warning(recipe,
"All MOS slits have the same offset: %.2f\n"
1393 "The LSS data reduction strategy is applied!",
1397 skylines_offsets_tag =
"SKY_SHIFTS_LONG_STD_MOS";
1400 skylines_offsets_tag =
"SKY_SHIFTS_LONG_SCI_MOS";
1405 skylines_offsets_tag =
"SKY_SHIFTS_LONG_STD_MXU";
1408 skylines_offsets_tag =
"SKY_SHIFTS_LONG_SCI_MXU";
1414 if (lss || treat_as_lss) {
1417 fors_science_exit(
"Cosmic rays correction for LSS or LSS-like "
1418 "data requires --skyglobal=true");
1422 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
1423 cpl_msg_error(recipe,
"Missing required input: %s", curv_coeff_tag);
1424 fors_science_exit(NULL);
1427 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
1428 cpl_msg_error(recipe,
"Too many in input: %s", curv_coeff_tag);
1429 fors_science_exit(NULL);
1432 cpl_propertylist_delete(header); header = NULL;
1439 cpl_msg_info(recipe,
"Remove the master bias...");
1441 const cpl_frame * bias_frame =
1442 cpl_frameset_find_const(frameset,
"MASTER_BIAS");
1445 fors_science_exit(
"Cannot load master bias");
1447 fors_subtract_bias(science_ima, bias);
1448 if (cpl_error_get_code() != CPL_ERROR_NONE)
1449 fors_science_exit(
"Cannot remove bias from scientific frame");
1455 cpl_msg_indent_less();
1456 cpl_msg_info(recipe,
"Load normalised flat field (if present)...");
1457 cpl_msg_indent_more();
1461 const cpl_frame * flat_frame =
1462 cpl_frameset_find_const(frameset, master_norm_flat_tag);
1466 cpl_msg_info(recipe,
"Apply flat field correction...");
1468 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1469 cpl_msg_error(recipe,
"Failure of flat field correction: %s",
1470 cpl_error_get_message());
1471 fors_science_exit(NULL);
1476 cpl_msg_error(recipe,
"Cannot load input %s for flat field "
1477 "correction", master_norm_flat_tag);
1478 fors_science_exit(NULL);
1482 spectra = science_ima->data;
1483 ccd_xsize = nx = cpl_image_get_size_x(spectra);
1484 ccd_ysize = ny = cpl_image_get_size_y(spectra);
1487 if (skyalign >= 0) {
1488 cpl_msg_indent_less();
1489 cpl_msg_info(recipe,
"Load input sky line catalog...");
1490 cpl_msg_indent_more();
1500 nlines = cpl_table_get_nrow(wavelengths);
1503 fors_science_exit(
"Empty input sky line catalog");
1505 if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
1506 cpl_msg_error(recipe,
"Missing column %s in input line "
1507 "catalog table", wcolumn);
1508 fors_science_exit(NULL);
1511 line = cpl_malloc(nlines *
sizeof(
double));
1513 for (i = 0; i < nlines; i++)
1514 line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
1516 cpl_table_delete(wavelengths); wavelengths = NULL;
1518 lines = cpl_vector_wrap(nlines, line);
1521 cpl_msg_info(recipe,
"No sky line catalog found in input - fine!");
1532 fors_science_exit(
"Cannot load slits location table");
1534 if (lss || treat_as_lss) {
1535 int first_row = cpl_table_get_double(slits,
"ybottom", 0, NULL);
1536 int last_row = cpl_table_get_double(slits,
"ytop", 0, NULL);
1542 dummy = cpl_image_extract(spectra, 1, ylow, nx, yhig);
1543 cpl_image_delete(spectra); spectra = dummy; dummy = NULL;
1544 ny = cpl_image_get_size_y(spectra);
1553 if (idscoeff == NULL)
1554 fors_science_exit(
"Cannot load wavelength calibration table");
1556 cpl_msg_indent_less();
1557 cpl_msg_info(recipe,
"Processing scientific spectra...");
1558 cpl_msg_indent_more();
1565 if (!(lss || treat_as_lss)) {
1567 if (polytraces == NULL)
1568 fors_science_exit(
"Cannot load spectral curvature table");
1573 int * slit_id = cpl_table_get_data_int(slits,
"slit_id");
1574 double * ytop = cpl_table_get_data_double(slits,
"ytop");
1575 double * ybottom = cpl_table_get_data_double(slits,
"ybottom");
1576 polytraces = cpl_table_new(2);
1577 cpl_table_new_column(polytraces,
"slit_id", CPL_TYPE_INT);
1578 cpl_table_new_column(polytraces,
"c0", CPL_TYPE_DOUBLE);
1579 cpl_table_set_int(polytraces,
"slit_id", 0, slit_id[0]);
1580 cpl_table_set_int(polytraces,
"slit_id", 1, slit_id[0]);
1581 cpl_table_set_double(polytraces,
"c0", 0, ytop[0]);
1582 cpl_table_set_double(polytraces,
"c0", 1, ybottom[0]);
1590 if (lss || treat_as_lss) {
1591 smapped = cpl_image_duplicate(spectra);
1594 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1597 startwavelength, endwavelength,
1598 dispersion, 1, coordinate);
1610 if (dispersion > 1.0)
1615 if (skyalign >= 0) {
1617 cpl_msg_info(recipe,
"Align wavelength solution to reference "
1618 "skylines applying %d order residual fit...", skyalign);
1621 cpl_msg_info(recipe,
"Align wavelength solution to reference "
1622 "skylines applying median offset...");
1625 if (lss || treat_as_lss) {
1627 startwavelength, endwavelength,
1628 idscoeff, lines, highres,
1629 skyalign, rainbow, 4);
1633 startwavelength, endwavelength,
1634 idscoeff, lines, highres, skyalign,
1640 cpl_msg_warning(recipe,
"Alignment of the wavelength solution "
1641 "to reference sky lines may be unreliable in "
1644 if (
dfs_save_table(frameset, offsets, skylines_offsets_tag, NULL,
1645 parlist, recipe, version))
1646 fors_science_exit(NULL);
1648 cpl_table_delete(offsets); offsets = NULL;
1651 if (cpl_error_get_code()) {
1652 if (cpl_error_get_code() == CPL_ERROR_INCOMPATIBLE_INPUT) {
1653 cpl_msg_error(recipe,
"The IDS coeff table is "
1654 "incompatible with the input slit position table.");
1656 cpl_msg_error(cpl_func,
"Error found in %s: %s",
1657 cpl_error_get_where(), cpl_error_get_message());
1658 fors_science_exit(NULL);
1660 cpl_msg_warning(recipe,
"Alignment of the wavelength solution "
1661 "to reference sky lines could not be done!");
1667 if (lss || treat_as_lss) {
1668 int first_row = cpl_table_get_double(slits,
"ybottom", 0, NULL);
1669 int last_row = cpl_table_get_double(slits,
"ytop", 0, NULL);
1675 wavemap = cpl_image_new(ccd_xsize, ccd_ysize, CPL_TYPE_FLOAT);
1676 cpl_image_copy(wavemap, rainbow, 1, ylow);
1678 wavemaplss = cpl_image_extract(wavemap, 1, ylow, nx, yhig);
1682 polytraces, reference,
1683 startwavelength, endwavelength,
1687 cpl_image_delete(rainbow); rainbow = NULL;
1688 cpl_image_delete(coordinate); coordinate = NULL;
1696 startwavelength, endwavelength,
1697 dispersion, idscoeff, 1);
1699 cpl_msg_indent_less();
1700 cpl_msg_info(recipe,
"Check applied wavelength against skylines...");
1701 cpl_msg_indent_more();
1704 dispersion, 6, highres);
1706 cpl_vector_delete(lines); lines = NULL;
1708 cpl_msg_info(recipe,
"Mean residual: %f", mean_rms);
1710 mean_rms = cpl_table_get_column_mean(idscoeff,
"error");
1712 cpl_msg_info(recipe,
"Mean model accuracy: %f pixel (%f A)",
1713 mean_rms, mean_rms * dispersion);
1715 header = cpl_propertylist_new();
1716 cpl_propertylist_update_double(header,
"CRPIX1", 1.0);
1717 cpl_propertylist_update_double(header,
"CRPIX2", 1.0);
1718 cpl_propertylist_update_double(header,
"CRVAL1",
1719 startwavelength + dispersion/2);
1720 cpl_propertylist_update_double(header,
"CRVAL2", 1.0);
1723 cpl_propertylist_update_double(header,
"CD1_1", dispersion);
1724 cpl_propertylist_update_double(header,
"CD1_2", 0.0);
1725 cpl_propertylist_update_double(header,
"CD2_1", 0.0);
1726 cpl_propertylist_update_double(header,
"CD2_2", 1.0);
1727 cpl_propertylist_update_string(header,
"CTYPE1",
"LINEAR");
1728 cpl_propertylist_update_string(header,
"CTYPE2",
"PIXEL");
1731 cpl_propertylist_update_string(header,
"BUNIT",
"ADU/s");
1732 dummy = cpl_image_divide_scalar_create(mapped_sky, alltime);
1733 if (
dfs_save_image(frameset, dummy, mapped_science_sky_tag, header,
1734 parlist, recipe, version))
1735 fors_science_exit(NULL);
1736 cpl_image_delete(dummy); dummy = NULL;
1739 if (skyglobal == 0 && skymedian == 0 && skylocal == 0) {
1740 cpl_image_delete(mapped_sky); mapped_sky = NULL;
1743 if (skyglobal || skylocal) {
1745 cpl_msg_indent_less();
1748 cpl_msg_info(recipe,
"Global sky determination...");
1749 cpl_msg_indent_more();
1750 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1751 if (lss || treat_as_lss) {
1760 cpl_image_subtract(spectra, skymap);
1763 cpl_image_delete(skymap); skymap = NULL;
1767 cpl_msg_info(recipe,
"Local sky determination...");
1768 cpl_msg_indent_more();
1770 startwavelength, endwavelength, dispersion);
1776 cpl_table_divide_scalar(sky,
"sky", alltime);
1779 NULL, parlist, recipe, version))
1780 fors_science_exit(NULL);
1782 cpl_table_delete(sky); sky = NULL;
1788 cpl_image_divide_scalar(skymap, alltime);
1791 save_header, parlist, recipe, version))
1792 fors_science_exit(NULL);
1794 cpl_image_delete(skymap); skymap = NULL;
1797 save_header, parlist, recipe, version))
1798 fors_science_exit(NULL);
1800 cpl_propertylist_delete(save_header); save_header = NULL;
1803 cpl_msg_info(recipe,
"Removing cosmic rays...");
1812 cpl_image_delete(smapped); smapped = NULL;
1814 if (lss || treat_as_lss) {
1815 smapped = cpl_image_duplicate(spectra);
1819 reference, startwavelength,
1820 endwavelength, dispersion,
1825 cpl_msg_warning(recipe,
"Sky subtraction failure");
1827 cpl_msg_warning(recipe,
"Cosmic rays removal not performed!");
1828 cosmics = skylocal = skyglobal = 0;
1832 cpl_image_delete(spectra); spectra = NULL;
1833 cpl_table_delete(polytraces); polytraces = NULL;
1834 if (lss || treat_as_lss)
1835 cpl_image_delete(wavemaplss); wavemaplss = NULL;
1837 if (skyalign >= 0) {
1839 cpl_propertylist_update_string(save_header,
"BUNIT",
"Angstrom");
1841 save_header, parlist, recipe, version))
1842 fors_science_exit(NULL);
1843 cpl_propertylist_delete(save_header); save_header = NULL;
1846 cpl_image_delete(wavemap); wavemap = NULL;
1849 startwavelength, endwavelength,
1850 dispersion, idscoeff, 1);
1852 cpl_image_delete(smapped); smapped = NULL;
1856 cpl_msg_indent_less();
1857 cpl_msg_info(recipe,
"Local sky determination...");
1858 cpl_msg_indent_more();
1863 cpl_image_subtract(mapped, skylocalmap);
1869 cpl_image_delete(skylocalmap); skylocalmap = NULL;
1873 if (have_phot && !standard) {
1874 if (cpl_frameset_count_tags(frameset, specphot_tag) == 0) {
1876 master_specphot_tag, 1);
1886 if (skyglobal || skymedian || skylocal) {
1888 skylocalmap = cpl_image_subtract_create(mapped_sky, mapped);
1890 cpl_image_delete(mapped_sky); mapped_sky = NULL;
1893 cpl_propertylist_update_string(header,
"BUNIT",
"ADU/s");
1894 dummy = cpl_image_divide_scalar_create(skylocalmap, alltime);
1896 parlist, recipe, version))
1897 fors_science_exit(NULL);
1898 cpl_image_delete(dummy); dummy = NULL;
1900 cpl_msg_indent_less();
1901 cpl_msg_info(recipe,
"Object detection...");
1902 cpl_msg_indent_more();
1904 if (cosmics || nscience > 1) {
1909 mapped_cleaned = cpl_image_duplicate(mapped);
1912 ext_radius, cont_radius);
1914 cpl_image_delete(mapped_cleaned); mapped_cleaned = NULL;
1917 cpl_image_delete(dummy); dummy = NULL;
1919 if (
dfs_save_table(frameset, slits, object_table_tag, NULL, parlist,
1921 fors_science_exit(NULL);
1923 cpl_msg_indent_less();
1924 cpl_msg_info(recipe,
"Object extraction...");
1925 cpl_msg_indent_more();
1928 ext_mode, ron, gain, 1);
1930 cpl_image_delete(skylocalmap); skylocalmap = NULL;
1934 cpl_table *ext_table = NULL;
1935 cpl_table *flux_table = NULL;
1944 airmass, flux_table,
1947 cpl_table_delete(ext_table);
1948 cpl_table_delete(flux_table);
1953 char *pipefile = NULL;
1959 fors_science_exit(
"Cannot reload scientific "
1970 "Product category", instrume))
1971 fors_science_exit(
"Cannot write product category "
1975 "DPR type", instrume))
1976 fors_science_exit(
"Missing keyword DPR TYPE in "
1977 "scientific frame header");
1980 "Template", instrume))
1981 fors_science_exit(
"Missing keyword TPL ID in "
1982 "scientific frame header");
1985 "ESO INS GRIS1 NAME", NULL,
1986 "Grism name", instrume))
1987 fors_science_exit(
"Missing keyword INS GRIS1 NAME "
1988 "in scientific frame header");
1991 "ESO INS GRIS1 ID", NULL,
1994 fors_science_exit(
"Missing keyword INS GRIS1 ID "
1995 "in scientific frame header");
1997 if (cpl_propertylist_has(qclist,
"ESO INS FILT1 NAME"))
1999 "ESO INS FILT1 NAME", NULL,
2000 "Filter name", instrume);
2003 "ESO INS COLL NAME", NULL,
2006 fors_science_exit(
"Missing keyword INS COLL NAME "
2007 "in scientific frame header");
2010 "ESO DET CHIP1 ID", NULL,
2013 fors_science_exit(
"Missing keyword DET CHIP1 ID "
2014 "in scientific frame header");
2017 "ESO INS MOS10 WID",
2018 "arcsec",
"Slit width",
2023 "arcsec",
"Slit width",
2026 fors_science_exit(
"Missing keyword "
2027 "ESO INS MOS10 WID in "
2028 "scientific frame header");
2031 fors_science_exit(
"Missing keyword "
2032 "ESO INS SLIT WID in "
2033 "scientific frame header");
2060 "ESO DET WIN1 BINX", NULL,
2061 "Binning factor along X",
2063 fors_science_exit(
"Missing keyword ESO "
2065 "in scientific frame header");
2068 "ESO DET WIN1 BINY", NULL,
2069 "Binning factor along Y",
2071 fors_science_exit(
"Missing keyword "
2072 "ESO DET WIN1 BINY "
2073 "in scientific frame header");
2076 "Archive name of input data",
2078 fors_science_exit(
"Missing keyword ARCFILE in "
2079 "scientific frame header");
2081 pipefile = dfs_generate_filename(specphot_tag);
2083 "Pipeline product name",
2085 fors_science_exit(
"Cannot write PIPEFILE to "
2098 dummy = cpl_image_new(wcount, 1, CPL_TYPE_FLOAT);
2099 data = cpl_image_get_data_float(dummy);
2100 map_table(dummy, wstart, wstep, photcal,
2101 "WAVE",
"EFFICIENCY");
2103 for (i = 0; i < wcount; i++) {
2104 sprintf(keyname,
"QC.SPEC.EFFICIENCY%d.LAMBDA",
2108 keyname,
"Angstrom",
2110 "efficiency evaluation",
2112 fors_science_exit(
"Cannot write wavelength of "
2113 "efficiency evaluation");
2116 sprintf(keyname,
"QC.SPEC.EFFICIENCY%d", i + 1);
2119 keyname,
"e-/photon",
2122 fors_science_exit(
"Cannot write wavelength of "
2123 "efficiency evaluation");
2127 cpl_image_delete(dummy); dummy = NULL;
2132 parlist, recipe, version))
2133 fors_science_exit(NULL);
2135 cpl_propertylist_delete(qclist); qclist = NULL;
2138 cpl_table_delete(photcal); photcal = NULL;
2144 cpl_image *calibrated;
2145 cpl_table *ext_table;
2150 if (cpl_frameset_count_tags(frameset, specphot_tag) == 0) {
2152 master_specphot_tag, 1);
2160 ext_table, startwavelength,
2161 dispersion, gain, alltime,
2163 cpl_propertylist_update_string(header,
"BUNIT",
2164 "10^(-16) erg/(cm^2 s Angstrom)");
2167 reduced_flux_science_tag, header,
2168 parlist, recipe, version)) {
2169 cpl_image_delete(calibrated);
2170 fors_science_exit(NULL);
2173 cpl_table_delete(ext_table);
2174 cpl_image_delete(calibrated);
2178 cpl_propertylist_update_string(header,
"BUNIT",
"ADU/s");
2179 cpl_image_divide_scalar(images[0], alltime);
2181 if (
dfs_save_image(frameset, images[0], reduced_science_tag, header,
2182 parlist, recipe, version))
2183 fors_science_exit(NULL);
2186 cpl_image_divide_scalar(images[1], alltime);
2189 parlist, recipe, version))
2190 fors_science_exit(NULL);
2192 cpl_image_delete(images[1]);
2195 cpl_image *calibrated;
2196 cpl_table *ext_table;
2202 ext_table, startwavelength,
2203 dispersion, gain, alltime,
2206 cpl_propertylist_update_string(header,
"BUNIT",
2207 "10^(-16) erg/(cm^2 s Angstrom)");
2210 reduced_flux_error_tag, header,
2211 parlist, recipe, version)) {
2212 cpl_image_delete(calibrated);
2213 fors_science_exit(NULL);
2216 cpl_table_delete(ext_table);
2217 cpl_image_delete(calibrated);
2222 cpl_propertylist_update_string(header,
"BUNIT",
"ADU/s");
2223 cpl_image_divide_scalar(images[2], alltime);
2225 if (
dfs_save_image(frameset, images[2], reduced_error_tag, header,
2226 parlist, recipe, version))
2227 fors_science_exit(NULL);
2229 cpl_image_delete(images[0]);
2230 cpl_image_delete(images[2]);
2235 cpl_msg_warning(recipe,
"No objects found: the products "
2236 "%s, %s, and %s are not created",
2237 reduced_science_tag, reduced_sky_tag,
2243 cpl_free(instrume); instrume = NULL;
2244 cpl_table_delete(slits); slits = NULL;
2246 if (skyalign >= 0) {
2248 parlist, recipe, version))
2249 fors_science_exit(NULL);
2252 cpl_table_delete(idscoeff); idscoeff = NULL;
2254 if (photometry && photcal) {
2255 cpl_image *calibrated;
2256 cpl_table *ext_table;
2262 ext_table, startwavelength,
2263 dispersion, gain, alltime,
2266 cpl_propertylist_update_string(header,
"BUNIT",
2267 "10^(-16) erg/(cm^2 s Angstrom)");
2270 mapped_flux_science_tag, header,
2271 parlist, recipe, version)) {
2272 cpl_image_delete(calibrated);
2273 fors_science_exit(NULL);
2276 cpl_table_delete(ext_table);
2277 cpl_image_delete(calibrated);
2281 cpl_propertylist_update_string(header,
"BUNIT",
"ADU/s");
2282 cpl_image_divide_scalar(mapped, alltime);
2285 parlist, recipe, version))
2286 fors_science_exit(NULL);
2288 cpl_table_delete(photcal); photcal = NULL;
2289 cpl_image_delete(mapped); mapped = NULL;
2290 cpl_propertylist_delete(header); header = NULL;
2292 if (cpl_error_get_code()) {
2293 cpl_msg_error(cpl_func,
"Error found in %s: %s",
2294 cpl_error_get_where(), cpl_error_get_message());
2295 fors_science_exit(NULL);
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_table * mos_photometric_calibration(cpl_image *spectra, double startwave, double dispersion, double gain, double exptime, cpl_table *ext_table, double airmass, cpl_table *flux_table, int order)
Produce instrument response curve, with some ancillary information.
void fors_image_multiply_scalar(fors_image *image, double s, double ds)
Multiply by scalar.
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
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_image * mos_propagate_photometry_error(cpl_image *spectra, cpl_image *errors, cpl_table *response, cpl_table *ext_table, double startwave, double dispersion, double gain, double exptime, double airmass)
Propagate errors from response curve and extracted spectra.
cpl_propertylist * dfs_load_header(cpl_frameset *frameset, const char *category, int ext)
Loading header associated to data of given category.
cpl_table * mos_load_slits_fors_mxu(cpl_propertylist *header)
Create slit location table from FITS header of FORS2-MXU data.
cpl_image ** mos_extract_objects(cpl_image *science, cpl_image *sky, cpl_table *objects, int extraction, double ron, double gain, int ncombined)
Extract detected objects from rectified scientific frame.
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_sky_map_super(cpl_image *spectra, cpl_image *wavemap, double dispersion, double factor, int minpoints, cpl_image *skymap)
Create a CCD median sky map.
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.
void fors_image_delete(fors_image **image)
Deallocate image and set pointer to NULL.
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.
void fors_image_divide_scalar(fors_image *image, double s, double ds)
Divide by scalar.
cpl_error_code fors_qc_start_group(cpl_propertylist *header, const char *qcdic_version, const char *instrument)
Initiate a new QC1 group.
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.
cpl_frameset * fors_frameset_extract(const cpl_frameset *frames, const char *tag)
Extract frames with given tag from frameset.
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
fors_image * fors_image_load(const cpl_frame *frame)
Load image.
cpl_table * mos_wavelength_align_lss(cpl_image *image, 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 (LSS).
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_image * mos_apply_photometry(cpl_image *spectra, cpl_table *response, cpl_table *ext_table, double startwave, double dispersion, double gain, double exptime, double airmass)
Apply response curve to extracted spectra.
cpl_error_code fors_qc_end_group(void)
Close current QC1 PAF file.
void fors_image_divide(fors_image *left, const fors_image *right)
Divide images.
cpl_error_code mos_clean_cosmics(cpl_image *image, float gain, float threshold, float ratio)
Remove cosmic rays from sky-subtracted CCD spectral exposure.
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.
const char * fors_get_license(void)
Get the pipeline copyright and license.