37 static int fors_extract_slits_create(cpl_plugin *);
38 static int fors_extract_slits_exec(cpl_plugin *);
39 static int fors_extract_slits_destroy(cpl_plugin *);
40 static int fors_extract_slits(cpl_parameterlist *, cpl_frameset *);
42 static char fors_extract_slits_description[] =
43 "This recipe is used to extract MOS/MXU slit spectra, following their\n"
44 "curvature, and to remap them into a spatially rectified image.\n"
45 "Please refer to the FORS Pipeline User's Manual for details about\n"
46 "the spectra remapping technique. Note however that the interpolation\n"
47 "is done exclusively along the spatial direction, and therefore the\n"
48 "output rectified image will have the same x size of the input spectral\n"
51 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
53 " DO category: Type: Explanation: Required:\n"
55 " or SCIENCE_UNBIAS_MXU\n"
56 " or SCIENCE_UNFLAT_MXU\n"
57 " or STANDARD_UNBIAS_MXU\n"
58 " or STANDARD_UNFLAT_MXU\n"
59 " or UNMAPPED_SCI_MXU\n"
60 " or UNMAPPED_STD_MXU\n"
61 " or UNMAPPED_SKY_SCI_MXU\n"
62 " or UNMAPPED_SKY_STD_MXU Calib Spectral frame Y\n"
63 " SLIT_LOCATION_DETECT_MXU\n"
64 " or SLIT_LOCATION_MXU Calib Master flat frame Y\n"
65 " CURV_COEFF_MXU Calib Spectral curvature Y\n"
66 " GRISM_TABLE Calib Grism table .\n\n"
68 " DO category: Data type: Explanation:\n"
69 " RECTIFIED_LAMP_MXU\n"
70 " or RECTIFIED_ALL_SCI_MXU\n"
71 " or RECTIFIED_ALL_STD_MXU\n"
72 " or RECTIFIED_SCI_MXU\n"
73 " or RECTIFIED_STD_MXU\n"
74 " or RECTIFIED_SKY_SCI_MXU\n"
75 " or RECTIFIED_SKY_STD_MXU FITS image Rectified slit spectra\n\n";
77 #define fors_extract_slits_exit(message) \
79 if (message) cpl_msg_error(recipe, message); \
80 cpl_image_delete(spectra); \
81 cpl_image_delete(spatial); \
82 cpl_table_delete(grism_table); \
83 cpl_table_delete(maskslits); \
84 cpl_table_delete(slits); \
85 cpl_table_delete(polytraces); \
86 cpl_propertylist_delete(header); \
87 cpl_msg_indent_less(); \
91 #define fors_extract_slits_exit_memcheck(message) \
93 if (message) cpl_msg_info(recipe, message); \
94 printf("free spectra (%p)\n", spectra); \
95 cpl_image_delete(spectra); \
96 printf("free spatial (%p)\n", spatial); \
97 cpl_image_delete(spatial); \
98 printf("free grism_table (%p)\n", grism_table); \
99 cpl_table_delete(grism_table); \
100 printf("free maskslits (%p)\n", maskslits); \
101 cpl_table_delete(maskslits); \
102 printf("free slits (%p)\n", slits); \
103 cpl_table_delete(slits); \
104 printf("free polytraces (%p)\n", polytraces); \
105 cpl_table_delete(polytraces); \
106 printf("free header (%p)\n", header); \
107 cpl_propertylist_delete(header); \
108 cpl_msg_indent_less(); \
126 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
127 cpl_plugin *plugin = &recipe->interface;
129 cpl_plugin_init(plugin,
132 CPL_PLUGIN_TYPE_RECIPE,
133 "fors_extract_slits",
134 "Spatial rectification of spectral image",
135 fors_extract_slits_description,
138 "This file is currently part of the FORS Instrument Pipeline\n"
139 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
140 "This program is free software; you can redistribute it and/or modify\n"
141 "it under the terms of the GNU General Public License as published by\n"
142 "the Free Software Foundation; either version 2 of the License, or\n"
143 "(at your option) any later version.\n\n"
144 "This program is distributed in the hope that it will be useful,\n"
145 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
146 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
147 "GNU General Public License for more details.\n\n"
148 "You should have received a copy of the GNU General Public License\n"
149 "along with this program; if not, write to the Free Software Foundation,\n"
150 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
151 fors_extract_slits_create,
152 fors_extract_slits_exec,
153 fors_extract_slits_destroy);
155 cpl_pluginlist_append(list, plugin);
171 static int fors_extract_slits_create(cpl_plugin *plugin)
180 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
181 recipe = (cpl_recipe *)plugin;
189 recipe->parameters = cpl_parameterlist_new();
195 p = cpl_parameter_new_value(
"fors.fors_extract_slits.dispersion",
197 "Expected spectral dispersion (Angstrom/pixel)",
198 "fors.fors_extract_slits",
200 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dispersion");
201 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
202 cpl_parameterlist_append(recipe->parameters, p);
208 p = cpl_parameter_new_value(
"fors.fors_extract_slits.startwavelength",
210 "Start wavelength in spectral extraction",
211 "fors.fors_extract_slits",
213 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"startwavelength");
214 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
215 cpl_parameterlist_append(recipe->parameters, p);
221 p = cpl_parameter_new_value(
"fors.fors_extract_slits.endwavelength",
223 "End wavelength in spectral extraction",
224 "fors.fors_extract_slits",
226 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"endwavelength");
227 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
228 cpl_parameterlist_append(recipe->parameters, p);
234 p = cpl_parameter_new_value(
"fors.fors_extract_slits.flux",
236 "Apply flux conservation",
237 "fors.fors_extract_slits",
239 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"flux");
240 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
241 cpl_parameterlist_append(recipe->parameters, p);
255 static int fors_extract_slits_exec(cpl_plugin *plugin)
259 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
260 recipe = (cpl_recipe *)plugin;
264 return fors_extract_slits(recipe->parameters, recipe->frames);
276 static int fors_extract_slits_destroy(cpl_plugin *plugin)
280 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
281 recipe = (cpl_recipe *)plugin;
285 cpl_parameterlist_delete(recipe->parameters);
300 static int fors_extract_slits(cpl_parameterlist *parlist,
301 cpl_frameset *frameset)
304 const char *recipe =
"fors_extract_slits";
312 double startwavelength;
313 double endwavelength;
320 cpl_image *spectra = NULL;
321 cpl_image *spatial = NULL;
322 cpl_table *grism_table = NULL;
323 cpl_table *slits = NULL;
324 cpl_table *polytraces = NULL;
325 cpl_table *maskslits = NULL;
326 cpl_propertylist *header = NULL;
333 const char *input_tag;
334 const char *output_tag;
335 const char *slit_location_tag;
336 const char *curv_coeff_tag;
371 int nslits_out_det = 0;
373 char *instrume = NULL;
376 cpl_msg_set_indentation(2);
383 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
384 cpl_msg_indent_more();
386 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
387 fors_extract_slits_exit(
"Too many in input: GRISM_TABLE");
392 "fors.fors_extract_slits.dispersion", grism_table);
394 if (dispersion <= 0.0)
395 fors_extract_slits_exit(
"Invalid spectral dispersion value");
398 "fors.fors_extract_slits.startwavelength", grism_table);
399 if (startwavelength > 1.0)
400 if (startwavelength < 3000.0 || startwavelength > 13000.0)
401 fors_extract_slits_exit(
"Invalid wavelength");
404 "fors.fors_extract_slits.endwavelength", grism_table);
405 if (endwavelength > 1.0) {
406 if (endwavelength < 3000.0 || endwavelength > 13000.0)
407 fors_extract_slits_exit(
"Invalid wavelength");
408 if (startwavelength < 1.0)
409 fors_extract_slits_exit(
"Invalid wavelength interval");
412 if (startwavelength > 1.0)
413 if (endwavelength - startwavelength <= 0.0)
414 fors_extract_slits_exit(
"Invalid wavelength interval");
417 "fors.fors_extract_slits.flux", NULL);
419 cpl_table_delete(grism_table); grism_table = NULL;
421 if (cpl_error_get_code())
422 fors_extract_slits_exit(
"Failure reading the configuration parameters");
425 cpl_msg_indent_less();
426 cpl_msg_info(recipe,
"Check input set-of-frames:");
427 cpl_msg_indent_more();
429 mxu = lamp_mxu = cpl_frameset_count_tags(frameset,
"LAMP_UNBIAS_MXU");
430 mos = lamp_mos = cpl_frameset_count_tags(frameset,
"LAMP_UNBIAS_MOS");
431 lss = lamp_lss = cpl_frameset_count_tags(frameset,
"LAMP_UNBIAS_LSS");
432 mxu += scib_mxu = cpl_frameset_count_tags(frameset,
"SCIENCE_UNBIAS_MXU");
433 mos += scib_mos = cpl_frameset_count_tags(frameset,
"SCIENCE_UNBIAS_MOS");
434 lss += scib_lss = cpl_frameset_count_tags(frameset,
"SCIENCE_UNBIAS_LSS");
435 mxu += scif_mxu = cpl_frameset_count_tags(frameset,
"SCIENCE_UNFLAT_MXU");
436 mos += scif_mos = cpl_frameset_count_tags(frameset,
"SCIENCE_UNFLAT_MOS");
437 lss += scif_lss = cpl_frameset_count_tags(frameset,
"SCIENCE_UNFLAT_LSS");
438 mxu += stab_mxu = cpl_frameset_count_tags(frameset,
"STANDARD_UNBIAS_MXU");
439 mos += stab_mos = cpl_frameset_count_tags(frameset,
"STANDARD_UNBIAS_MOS");
440 lss += stab_lss = cpl_frameset_count_tags(frameset,
"STANDARD_UNBIAS_LSS");
441 mxu += staf_mxu = cpl_frameset_count_tags(frameset,
"STANDARD_UNFLAT_MXU");
442 mos += staf_mos = cpl_frameset_count_tags(frameset,
"STANDARD_UNFLAT_MOS");
443 lss += staf_lss = cpl_frameset_count_tags(frameset,
"STANDARD_UNFLAT_LSS");
444 mxu += sciu_mxu = cpl_frameset_count_tags(frameset,
"UNMAPPED_SCI_MXU");
445 mos += sciu_mos = cpl_frameset_count_tags(frameset,
"UNMAPPED_SCI_MOS");
446 lss += sciu_lss = cpl_frameset_count_tags(frameset,
"UNMAPPED_SCI_LSS");
447 mxu += stau_mxu = cpl_frameset_count_tags(frameset,
"UNMAPPED_STD_MXU");
448 mos += stau_mos = cpl_frameset_count_tags(frameset,
"UNMAPPED_STD_MOS");
449 lss += stau_lss = cpl_frameset_count_tags(frameset,
"UNMAPPED_STD_LSS");
450 mxu += scis_mxu = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_SCI_MXU");
451 mos += scis_mos = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_SCI_MOS");
452 lss += scis_lss = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_SCI_LSS");
453 mxu += stas_mxu = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_STD_MXU");
454 mos += stas_mos = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_STD_MOS");
455 lss += stas_lss = cpl_frameset_count_tags(frameset,
"UNMAPPED_SKY_STD_LSS");
457 nframes = mos + mxu + lss;
460 fors_extract_slits_exit(
"Missing input spectral frame");
463 cpl_msg_error(recipe,
464 "Too many input spectral frames (%d > 1)", nframes);
465 fors_extract_slits_exit(NULL);
469 fors_extract_slits_exit(
"Use this recipe just with MOS/MXU data.");
472 slit_l = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_MXU");
473 slit_d = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_DETECT_MXU");
476 slit_l = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_MOS");
477 slit_d = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_DETECT_MOS");
480 nframes = slit_l + slit_d;
483 fors_extract_slits_exit(
"Missing input slit location table");
486 cpl_msg_error(recipe,
487 "Too many input slit location tables (%d > 1)", nframes);
488 fors_extract_slits_exit(NULL);
493 slit_location_tag =
"SLIT_LOCATION_MXU";
495 slit_location_tag =
"SLIT_LOCATION_MOS";
499 slit_location_tag =
"SLIT_LOCATION_DETECT_MXU";
501 slit_location_tag =
"SLIT_LOCATION_DETECT_MOS";
505 curv_coeff_tag =
"CURV_COEFF_MXU";
507 curv_coeff_tag =
"CURV_COEFF_MOS";
510 input_tag =
"LAMP_UNBIAS_MXU";
511 output_tag =
"RECTIFIED_LAMP_MXU";
514 input_tag =
"LAMP_UNBIAS_MOS";
515 output_tag =
"RECTIFIED_LAMP_MOS";
518 input_tag =
"SCIENCE_UNBIAS_MXU";
519 output_tag =
"RECTIFIED_ALL_SCI_MXU";
522 input_tag =
"SCIENCE_UNBIAS_MOS";
523 output_tag =
"RECTIFIED_ALL_SCI_MOS";
526 input_tag =
"SCIENCE_UNFLAT_MXU";
527 output_tag =
"RECTIFIED_ALL_SCI_MXU";
530 input_tag =
"SCIENCE_UNFLAT_MOS";
531 output_tag =
"RECTIFIED_ALL_SCI_MOS";
534 input_tag =
"STANDARD_UNBIAS_MXU";
535 output_tag =
"RECTIFIED_ALL_STD_MXU";
538 input_tag =
"STANDARD_UNBIAS_MOS";
539 output_tag =
"RECTIFIED_ALL_STD_MOS";
542 input_tag =
"STANDARD_UNFLAT_MXU";
543 output_tag =
"RECTIFIED_ALL_STD_MXU";
546 input_tag =
"STANDARD_UNFLAT_MOS";
547 output_tag =
"RECTIFIED_ALL_STD_MOS";
550 input_tag =
"UNMAPPED_SCI_MXU";
551 output_tag =
"RECTIFIED_SCI_MXU";
554 input_tag =
"UNMAPPED_SCI_MOS";
555 output_tag =
"RECTIFIED_SCI_MOS";
558 input_tag =
"UNMAPPED_STD_MXU";
559 output_tag =
"RECTIFIED_STD_MXU";
562 input_tag =
"UNMAPPED_STD_MOS";
563 output_tag =
"RECTIFIED_STD_MOS";
566 input_tag =
"UNMAPPED_SKY_SCI_MXU";
567 output_tag =
"RECTIFIED_SKY_SCI_MXU";
570 input_tag =
"UNMAPPED_SKY_SCI_MOS";
571 output_tag =
"RECTIFIED_SKY_SCI_MOS";
574 input_tag =
"UNMAPPED_SKY_STD_MXU";
575 output_tag =
"RECTIFIED_SKY_STD_MXU";
578 input_tag =
"UNMAPPED_SKY_STD_MOS";
579 output_tag =
"RECTIFIED_SKY_STD_MOS";
585 fors_extract_slits_exit(
"Cannot load master flat frame header");
596 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
598 cpl_table_delete(maskslits); maskslits = NULL;
601 cpl_msg_error(recipe,
"All slits have the same offset: %.2f mm\n"
602 "The LSS data reduction strategy must be applied.",
604 fors_extract_slits_exit(NULL);
608 fors_extract_slits_exit(
"Input frames are not from the same grism");
611 fors_extract_slits_exit(
"Input frames are not from the same filter");
614 fors_extract_slits_exit(
"Input frames are not from the same chip");
622 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
623 if (instrume == NULL)
624 fors_extract_slits_exit(
"Missing keyword INSTRUME in master "
627 if (instrume[4] ==
'1')
628 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
629 if (instrume[4] ==
'2')
630 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
632 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
634 if (cpl_error_get_code() != CPL_ERROR_NONE)
635 fors_extract_slits_exit(
"Missing keyword ESO INS GRIS1 WLEN "
636 "in master flat frame header");
638 if (reference < 3000.0)
641 if (reference < 3000.0 || reference > 13000.0) {
642 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
643 "keyword ESO INS GRIS1 WLEN in master flat header",
645 fors_extract_slits_exit(NULL);
648 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
650 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
652 if (cpl_error_get_code() != CPL_ERROR_NONE)
653 fors_extract_slits_exit(
"Missing keyword ESO DET WIN1 BINX "
654 "in master flat header");
658 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
659 "working dispersion used is %f A/pixel", rebin,
663 cpl_msg_indent_less();
664 cpl_msg_info(recipe,
"Load input frames...");
665 cpl_msg_indent_more();
667 spectra =
dfs_load_image(frameset, input_tag, CPL_TYPE_FLOAT, 0, 0);
669 fors_extract_slits_exit(
"Cannot load input spectral frame");
673 fors_extract_slits_exit(
"Cannot load slits location table");
677 fors_extract_slits_exit(
"Cannot load spectral curvature table");
680 startwavelength, endwavelength,
681 dispersion, flux, NULL);
683 cpl_image_delete(spectra); spectra = NULL;
684 cpl_table_delete(polytraces); polytraces = NULL;
685 cpl_table_delete(slits); slits = NULL;
687 cpl_propertylist_delete(header); header = NULL;
688 header = cpl_propertylist_new();
690 cpl_propertylist_update_double(header,
"CRPIX2", 1.0);
691 cpl_propertylist_update_double(header,
"CRVAL2", 1.0);
693 cpl_propertylist_update_double(header,
"CD1_1", 1.0);
694 cpl_propertylist_update_double(header,
"CD1_2", 0.0);
695 cpl_propertylist_update_double(header,
"CD2_1", 0.0);
696 cpl_propertylist_update_double(header,
"CD2_2", 1.0);
697 cpl_propertylist_update_string(header,
"CTYPE1",
"LINEAR");
698 cpl_propertylist_update_string(header,
"CTYPE2",
"PIXEL");
701 header, parlist, recipe, version))
702 fors_extract_slits_exit(NULL);
704 cpl_image_delete(spatial); spatial = NULL;
705 cpl_propertylist_delete(header); header = 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.
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.
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_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.
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 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.
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.