37 static int fors_subtract_sky_create(cpl_plugin *);
38 static int fors_subtract_sky_exec(cpl_plugin *);
39 static int fors_subtract_sky_destroy(cpl_plugin *);
40 static int fors_subtract_sky(cpl_parameterlist *, cpl_frameset *);
42 static char fors_subtract_sky_description[] =
43 "This recipe is used to subtract the sky emission from unrebinned slit\n"
44 "spectra. This is obtained by robust fitting (i.e., excluding the signal\n"
45 "from possible point-like objects in slit) of the emission along the CCD\n"
46 "columns within each spectrum). This method doesn't work if extended\n"
47 "objects are in slit (it really destroys the object spectra), and is\n"
48 "not applicable to LSS data. The input scientific frames are produced\n"
49 "by the recipes fors_remove_bias and fors_flatfield.\n"
51 "This recipe cannot be applied to LSS or long-slit like data (MOS/MXU with\n"
52 "all slits at the same offset). No automatic recipe is available for this.\n"
53 "Please refer to the FORS Pipeline User's Manual for more details.\n"
55 "In the table below the MXU acronym can be alternatively read as MOS, and\n"
58 " DO category: Type: Explanation: Required:\n"
59 " SCIENCE_UNBIAS_MXU\n"
60 " or SCIENCE_UNFLAT_MXU\n"
61 " or STANDARD_UNBIAS_MXU\n"
62 " or STANDARD_UNFLAT_MXU Calib Frame with sky lines Y\n"
63 " CURV_COEFF_MXU Calib Spectral curvature Y\n"
64 " SLIT_LOCATION_MXU Calib Slit location on CCD Y\n"
65 " GRISM_TABLE Calib Grism table .\n\n"
67 " DO category: Data type: Explanation:\n"
69 " or UNMAPPED_STD_MXU FITS image Sky subtracted scientific frame\n"
70 " UNMAPPED_SKY_SCI_MXU\n"
71 " or UNMAPPED_SKY_STD_MXU FITS image Subtracted sky frame\n\n";
73 #define fors_subtract_sky_exit(message) \
75 if (message) cpl_msg_error(recipe, message); \
76 cpl_image_delete(spectra); \
77 cpl_image_delete(skymap); \
78 cpl_table_delete(grism_table); \
79 cpl_table_delete(maskslits); \
80 cpl_table_delete(slits); \
81 cpl_table_delete(polytraces); \
82 cpl_propertylist_delete(header); \
83 cpl_msg_indent_less(); \
87 #define fors_subtract_sky_exit_memcheck(message) \
89 if (message) cpl_msg_info(recipe, message); \
90 printf("free spectra (%p)\n", spectra); \
91 cpl_image_delete(spectra); \
92 printf("free skymap (%p)\n", skymap); \
93 cpl_image_delete(skymap); \
94 printf("free grism_table (%p)\n", grism_table); \
95 cpl_table_delete(grism_table); \
96 printf("free maskslits (%p)\n", maskslits); \
97 cpl_table_delete(maskslits); \
98 printf("free slits (%p)\n", slits); \
99 cpl_table_delete(slits); \
100 printf("free polytraces (%p)\n", polytraces); \
101 cpl_table_delete(polytraces); \
102 printf("free header (%p)\n", header); \
103 cpl_propertylist_delete(header); \
104 cpl_msg_indent_less(); \
122 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
123 cpl_plugin *plugin = &recipe->interface;
125 cpl_plugin_init(plugin,
128 CPL_PLUGIN_TYPE_RECIPE,
130 "Subtract sky from scientific spectra",
131 fors_subtract_sky_description,
134 "This file is currently part of the FORS Instrument Pipeline\n"
135 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
136 "This program is free software; you can redistribute it and/or modify\n"
137 "it under the terms of the GNU General Public License as published by\n"
138 "the Free Software Foundation; either version 2 of the License, or\n"
139 "(at your option) any later version.\n\n"
140 "This program is distributed in the hope that it will be useful,\n"
141 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
142 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
143 "GNU General Public License for more details.\n\n"
144 "You should have received a copy of the GNU General Public License\n"
145 "along with this program; if not, write to the Free Software Foundation,\n"
146 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
147 fors_subtract_sky_create,
148 fors_subtract_sky_exec,
149 fors_subtract_sky_destroy);
151 cpl_pluginlist_append(list, plugin);
167 static int fors_subtract_sky_create(cpl_plugin *plugin)
176 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
177 recipe = (cpl_recipe *)plugin;
185 recipe->parameters = cpl_parameterlist_new();
191 p = cpl_parameter_new_value(
"fors.fors_subtract_sky.dispersion",
193 "Expected spectral dispersion (Angstrom/pixel)",
194 "fors.fors_subtract_sky",
196 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dispersion");
197 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
198 cpl_parameterlist_append(recipe->parameters, p);
204 p = cpl_parameter_new_value(
"fors.fors_subtract_sky.startwavelength",
206 "Start wavelength in spectral extraction",
207 "fors.fors_subtract_sky",
209 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"startwavelength");
210 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
211 cpl_parameterlist_append(recipe->parameters, p);
217 p = cpl_parameter_new_value(
"fors.fors_subtract_sky.endwavelength",
219 "End wavelength in spectral extraction",
220 "fors.fors_subtract_sky",
222 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"endwavelength");
223 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
224 cpl_parameterlist_append(recipe->parameters, p);
230 p = cpl_parameter_new_value(
"fors.fors_subtract_sky.cosmics",
232 "Eliminate cosmic rays hits",
233 "fors.fors_subtract_sky",
235 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cosmics");
236 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
237 cpl_parameterlist_append(recipe->parameters, p);
251 static int fors_subtract_sky_exec(cpl_plugin *plugin)
255 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
256 recipe = (cpl_recipe *)plugin;
260 return fors_subtract_sky(recipe->parameters, recipe->frames);
272 static int fors_subtract_sky_destroy(cpl_plugin *plugin)
276 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
277 recipe = (cpl_recipe *)plugin;
281 cpl_parameterlist_delete(recipe->parameters);
296 static int fors_subtract_sky(cpl_parameterlist *parlist,
297 cpl_frameset *frameset)
300 const char *recipe =
"fors_subtract_sky";
308 double startwavelength;
309 double endwavelength;
316 cpl_image *spectra = NULL;
317 cpl_image *skymap = NULL;
318 cpl_table *grism_table = NULL;
319 cpl_table *polytraces = NULL;
320 cpl_table *slits = NULL;
321 cpl_table *maskslits = NULL;
322 cpl_propertylist *header = NULL;
329 const char *slit_location_tag;
330 const char *input_tag;
331 const char *curv_coeff_tag;
332 const char *unmapped_tag;
333 const char *unmapped_sky_tag;
348 int nslits_out_det = 0;
350 char *instrume = NULL;
353 cpl_msg_set_indentation(2);
360 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
361 cpl_msg_indent_more();
363 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
364 fors_subtract_sky_exit(
"Too many in input: GRISM_TABLE");
369 "fors.fors_subtract_sky.dispersion", grism_table);
371 if (dispersion <= 0.0)
372 fors_subtract_sky_exit(
"Invalid spectral dispersion value");
375 "fors.fors_subtract_sky.startwavelength", grism_table);
376 if (startwavelength > 1.0)
377 if (startwavelength < 3000.0 || startwavelength > 13000.0)
378 fors_subtract_sky_exit(
"Invalid wavelength");
381 "fors.fors_subtract_sky.endwavelength", grism_table);
382 if (endwavelength > 1.0) {
383 if (endwavelength < 3000.0 || endwavelength > 13000.0)
384 fors_subtract_sky_exit(
"Invalid wavelength");
385 if (startwavelength < 1.0)
386 fors_subtract_sky_exit(
"Invalid wavelength interval");
389 if (startwavelength > 1.0)
390 if (endwavelength - startwavelength <= 0.0)
391 fors_subtract_sky_exit(
"Invalid wavelength interval");
394 "fors.fors_subtract_sky.cosmics", NULL);
396 cpl_table_delete(grism_table); grism_table = NULL;
398 if (cpl_error_get_code())
399 fors_subtract_sky_exit(
"Failure reading the configuration parameters");
402 cpl_msg_indent_less();
403 cpl_msg_info(recipe,
"Check input set-of-frames:");
404 cpl_msg_indent_more();
406 mxu = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_MXU");
407 mos = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_MOS");
408 lss = cpl_frameset_count_tags(frameset,
"SLIT_LOCATION_LSS");
411 fors_subtract_sky_exit(
"Use this recipe just with MOS/MXU data.");
416 fors_subtract_sky_exit(
"Missing input slit location table");
419 cpl_msg_error(recipe,
420 "Too many input slit location tables (%d > 1)", nframes);
421 fors_subtract_sky_exit(NULL);
425 curv_coeff_tag =
"CURV_COEFF_MXU";
427 curv_coeff_tag =
"CURV_COEFF_MXU";
430 nframes = cpl_frameset_count_tags(frameset, curv_coeff_tag);
433 cpl_msg_error(recipe,
"Missing input %s", curv_coeff_tag);
434 fors_subtract_sky_exit(NULL);
437 cpl_msg_error(recipe,
"Too many input %s (%d > 1)", curv_coeff_tag,
439 fors_subtract_sky_exit(NULL);
443 rec_scib = cpl_frameset_count_tags(frameset,
"SCIENCE_UNBIAS_MXU");
444 rec_stdb = cpl_frameset_count_tags(frameset,
"STANDARD_UNBIAS_MXU");
445 rec_scif = cpl_frameset_count_tags(frameset,
"SCIENCE_UNFLAT_MXU");
446 rec_stdf = cpl_frameset_count_tags(frameset,
"STANDARD_UNFLAT_MXU");
449 rec_scib = cpl_frameset_count_tags(frameset,
"SCIENCE_UNBIAS_MOS");
450 rec_stdb = cpl_frameset_count_tags(frameset,
"STANDARD_UNBIAS_MOS");
451 rec_scif = cpl_frameset_count_tags(frameset,
"SCIENCE_UNFLAT_MOS");
452 rec_stdf = cpl_frameset_count_tags(frameset,
"STANDARD_UNFLAT_MOS");
455 nframes = rec_scib + rec_stdb + rec_scif + rec_stdf;
458 fors_subtract_sky_exit(
"Missing input scientific spectra");
461 cpl_msg_error(recipe,
"Too many input scientific spectra (%d > 1)",
463 fors_subtract_sky_exit(NULL);
468 input_tag =
"SCIENCE_UNBIAS_MXU";
469 slit_location_tag =
"SLIT_LOCATION_MXU";
470 unmapped_tag =
"UNMAPPED_SCI_MXU";
471 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MXU";
474 input_tag =
"SCIENCE_UNBIAS_MOS";
475 slit_location_tag =
"SLIT_LOCATION_MOS";
476 unmapped_tag =
"UNMAPPED_SCI_MOS";
477 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MOS";
482 input_tag =
"STANDARD_UNBIAS_MXU";
483 slit_location_tag =
"SLIT_LOCATION_MXU";
484 unmapped_tag =
"UNMAPPED_STD_MXU";
485 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MXU";
488 input_tag =
"STANDARD_UNBIAS_MOS";
489 slit_location_tag =
"SLIT_LOCATION_MOS";
490 unmapped_tag =
"UNMAPPED_STD_MOS";
491 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MOS";
496 input_tag =
"SCIENCE_UNFLAT_MXU";
497 slit_location_tag =
"SLIT_LOCATION_MXU";
498 unmapped_tag =
"UNMAPPED_SCI_MXU";
499 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MXU";
502 input_tag =
"SCIENCE_UNFLAT_MOS";
503 slit_location_tag =
"SLIT_LOCATION_MOS";
504 unmapped_tag =
"UNMAPPED_SCI_MOS";
505 unmapped_sky_tag =
"UNMAPPED_SKY_SCI_MOS";
510 input_tag =
"STANDARD_UNFLAT_MXU";
511 slit_location_tag =
"SLIT_LOCATION_MXU";
512 unmapped_tag =
"UNMAPPED_STD_MXU";
513 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MXU";
516 input_tag =
"STANDARD_UNFLAT_MOS";
517 slit_location_tag =
"SLIT_LOCATION_MOS";
518 unmapped_tag =
"UNMAPPED_STD_MOS";
519 unmapped_sky_tag =
"UNMAPPED_SKY_STD_MOS";
527 fors_subtract_sky_exit(
"Cannot load scientific frame header");
538 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
540 cpl_table_delete(maskslits); maskslits = NULL;
543 fors_subtract_sky_exit(
"This recipe cannot process MOS/MXU "
544 "data with all slits at the same offset.");
548 fors_subtract_sky_exit(
"Input frames are not from the same grism");
551 fors_subtract_sky_exit(
"Input frames are not from the same filter");
554 fors_subtract_sky_exit(
"Input frames are not from the same chip");
562 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
563 if (instrume == NULL)
564 fors_subtract_sky_exit(
"Missing keyword INSTRUME in reference frame "
567 if (instrume[4] ==
'1')
568 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
569 if (instrume[4] ==
'2')
570 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
572 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
574 if (cpl_error_get_code() != CPL_ERROR_NONE)
575 fors_subtract_sky_exit(
"Missing keyword ESO INS GRIS1 WLEN "
576 "in reference frame header");
578 if (reference < 3000.0)
581 if (reference < 3000.0 || reference > 13000.0) {
582 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
583 "keyword ESO INS GRIS1 WLEN in reference frame header",
585 fors_subtract_sky_exit(NULL);
588 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
590 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
592 if (cpl_error_get_code() != CPL_ERROR_NONE)
593 fors_subtract_sky_exit(
"Missing keyword ESO DET WIN1 BINX "
594 "in reference frame header");
598 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
599 "working dispersion used is %f A/pixel", rebin,
604 gain = cpl_propertylist_get_double(header,
"ESO DET OUT1 CONAD");
606 if (cpl_error_get_code() != CPL_ERROR_NONE)
607 fors_subtract_sky_exit(
"Missing keyword ESO DET OUT1 CONAD in "
608 "scientific frame header");
610 cpl_msg_info(recipe,
"The gain factor is: %.2f e-/ADU", gain);
614 cpl_msg_indent_less();
615 cpl_msg_info(recipe,
"Load input frames...");
616 cpl_msg_indent_more();
618 spectra =
dfs_load_image(frameset, input_tag, CPL_TYPE_FLOAT, 0, 0);
620 fors_subtract_sky_exit(
"Cannot load input scientific frame");
624 fors_subtract_sky_exit(
"Cannot load slits location table");
627 if (polytraces == NULL)
628 fors_subtract_sky_exit(
"Cannot load spectral curvature table");
630 cpl_msg_indent_less();
631 cpl_msg_info(recipe,
"Local sky determination...");
632 cpl_msg_indent_more();
634 startwavelength, endwavelength, dispersion);
636 cpl_table_delete(polytraces); polytraces = NULL;
637 cpl_table_delete(slits); slits = NULL;
640 cpl_msg_info(recipe,
"Removing cosmic rays...");
645 header, parlist, recipe, version))
646 fors_subtract_sky_exit(NULL);
648 cpl_image_delete(spectra); spectra = NULL;
651 header, parlist, recipe, version))
652 fors_subtract_sky_exit(NULL);
654 cpl_image_delete(skymap); skymap = NULL;
656 cpl_propertylist_delete(header); header = NULL;
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.
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.
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.
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.