36 #include <fors_flat_normalise.h>
38 static int fors_normalise_flat_create(cpl_plugin *);
39 static int fors_normalise_flat_exec(cpl_plugin *);
40 static int fors_normalise_flat_destroy(cpl_plugin *);
41 static int fors_normalise_flat(cpl_parameterlist *, cpl_frameset *);
43 static char fors_normalise_flat_description[] =
44 "This recipe is used to normalise a master flat field frame dividing it\n"
45 "by its large scale illumination trend. This recipe can be applied both\n"
46 "to generic multi-slit (MOS/MXU) and to long slit exposures (either LSS, or\n"
47 "LSS-like MOS/MXU), even if different normalisation methods are applied in\n"
48 "such different cases. The input master flat field image is the product\n"
49 "of the recipe fors_flat. The input spectral curvature table, product of\n"
50 "the recipe fors_detect_spectra, is only required in the case of multi-slit\n"
53 "In the case of multi-slit data, the flat field spectra are spatially\n"
54 "rectified, heavily smoothed, and then mapped back on the CCD. Then the\n"
55 "master flat image is divided by its smoothed counterpart. The smoothing\n"
56 "may be obtained either by applying a running median filter of specified\n"
57 "sizes, or by polynomial fitting along the dispersion direction performed\n"
58 "independently for each row of the spatially remapped spectra.\n"
60 "In the case of long-slit data, the smoothing can still be obtained either\n"
61 "by applying a running median filter or by polynomial fitting, but the\n"
62 "polynomial fitting will be performed along the spatial direction, for\n"
63 "each column of the spectrum.\n"
65 "In the table below the MXU acronym can be alternatively read as MOS or\n"
68 " DO category: Type: Explanation: Required:\n"
69 " MASTER_SCREEN_FLAT_MXU Calib Master flat frame Y\n"
70 " CURV_COEFF_MXU Calib Spectral curvature .\n"
71 " SLIT_LOCATION_MXU Calib Spectral curvature .\n"
72 " GRISM_TABLE Calib Grism table .\n\n"
74 " DO category: Data type: Explanation:\n"
75 " MASTER_NORM_FLAT_MXU FITS image Normalised flat field\n\n";
77 #define fors_normalise_flat_exit(message) \
79 if (message) cpl_msg_error(recipe, message); \
80 cpl_image_delete(master_flat); \
81 cpl_image_delete(spatial); \
82 cpl_image_delete(coordinate); \
83 cpl_image_delete(smo_flat); \
84 cpl_table_delete(grism_table); \
85 cpl_table_delete(maskslits); \
86 cpl_table_delete(slits); \
87 cpl_table_delete(polytraces); \
88 cpl_propertylist_delete(header); \
89 cpl_msg_indent_less(); \
93 #define fors_normalise_flat_exit_memcheck(message) \
95 if (message) cpl_msg_info(recipe, message); \
96 printf("free master_flat (%p)\n", master_flat); \
97 cpl_image_delete(master_flat); \
98 printf("free spatial (%p)\n", spatial); \
99 cpl_image_delete(spatial); \
100 printf("free coordinate (%p)\n", coordinate); \
101 cpl_image_delete(coordinate); \
102 printf("free smo_flat (%p)\n", smo_flat); \
103 cpl_image_delete(smo_flat); \
104 printf("free grism_table (%p)\n", grism_table); \
105 cpl_table_delete(grism_table); \
106 printf("free maskslits (%p)\n", maskslits); \
107 cpl_table_delete(maskslits); \
108 printf("free slits (%p)\n", slits); \
109 cpl_table_delete(slits); \
110 printf("free polytraces (%p)\n", polytraces); \
111 cpl_table_delete(polytraces); \
112 printf("free header (%p)\n", header); \
113 cpl_propertylist_delete(header); \
114 cpl_msg_indent_less(); \
132 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
133 cpl_plugin *plugin = &recipe->interface;
135 cpl_plugin_init(plugin,
138 CPL_PLUGIN_TYPE_RECIPE,
139 "fors_normalise_flat",
140 "Normalise master flat spectrum",
141 fors_normalise_flat_description,
144 "This file is currently part of the FORS Instrument Pipeline\n"
145 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
146 "This program is free software; you can redistribute it and/or modify\n"
147 "it under the terms of the GNU General Public License as published by\n"
148 "the Free Software Foundation; either version 2 of the License, or\n"
149 "(at your option) any later version.\n\n"
150 "This program is distributed in the hope that it will be useful,\n"
151 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
152 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
153 "GNU General Public License for more details.\n\n"
154 "You should have received a copy of the GNU General Public License\n"
155 "along with this program; if not, write to the Free Software Foundation,\n"
156 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
157 fors_normalise_flat_create,
158 fors_normalise_flat_exec,
159 fors_normalise_flat_destroy);
161 cpl_pluginlist_append(list, plugin);
177 static int fors_normalise_flat_create(cpl_plugin *plugin)
186 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
187 recipe = (cpl_recipe *)plugin;
195 recipe->parameters = cpl_parameterlist_new();
201 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.dispersion",
203 "Expected spectral dispersion (Angstrom/pixel)",
204 "fors.fors_normalise_flat",
206 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dispersion");
207 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
208 cpl_parameterlist_append(recipe->parameters, p);
214 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.startwavelength",
216 "Start wavelength in spectral extraction",
217 "fors.fors_normalise_flat",
219 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"startwavelength");
220 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
221 cpl_parameterlist_append(recipe->parameters, p);
227 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.endwavelength",
229 "End wavelength in spectral extraction",
230 "fors.fors_normalise_flat",
232 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"endwavelength");
233 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
234 cpl_parameterlist_append(recipe->parameters, p);
240 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.spa_polydegree",
242 "Polynomial degree for the flat field fitting "
243 "along spatial direction",
244 "fors.fors_normalise_flat",
246 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"spa_polydegree");
247 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
248 cpl_parameterlist_append(recipe->parameters, p);
255 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.sradius",
257 "Smooth box radius for flat field along "
258 "spatial direction (used if spa_knots < 0)",
259 "fors.fors_normalise_flat",
261 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sradius");
262 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
263 cpl_parameterlist_append(recipe->parameters, p);
269 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.disp_nknots",
271 "Number of knots in flat field fitting "
272 "splines along dispersion direction",
273 "fors.fors_normalise_flat",
275 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"disp_nknots");
276 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
277 cpl_parameterlist_append(recipe->parameters, p);
283 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.dradius",
285 "Smooth box radius for flat field along "
286 "dispersion direction (if disp_knots < 0)",
287 "fors.fors_normalise_flat",
289 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dradius");
290 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
291 cpl_parameterlist_append(recipe->parameters, p);
297 p = cpl_parameter_new_value(
"fors.fors_normalise_flat.splfit_threshold",
299 "Threshold percentage for flat spline fitting"
300 "with respect to the maximum",
301 "fors.fors_normalise_flat",
303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"splfit_threshold");
304 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
305 cpl_parameterlist_append(recipe->parameters, p);
319 static int fors_normalise_flat_exec(cpl_plugin *plugin)
323 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
324 recipe = (cpl_recipe *)plugin;
331 return fors_normalise_flat(recipe->parameters, recipe->frames);
343 static int fors_normalise_flat_destroy(cpl_plugin *plugin)
347 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
348 recipe = (cpl_recipe *)plugin;
352 cpl_parameterlist_delete(recipe->parameters);
367 static int fors_normalise_flat(cpl_parameterlist *parlist,
368 cpl_frameset *frameset)
371 const char *recipe =
"fors_normalise_flat";
379 double startwavelength;
380 double endwavelength;
385 float splfit_threshold;
391 cpl_image *master_flat = NULL;
392 cpl_image *smo_flat = NULL;
393 cpl_image *coordinate = NULL;
394 cpl_image *spatial = NULL;
395 cpl_table *grism_table = NULL;
396 cpl_table *slits = NULL;
397 cpl_table *polytraces = NULL;
398 cpl_table *maskslits = NULL;
399 cpl_propertylist *header = NULL;
406 const char *master_flat_tag;
407 const char *master_norm_flat_tag;
408 const char *slit_location_tag;
409 const char *curv_coeff_tag;
418 char *instrume = NULL;
421 cpl_msg_set_indentation(2);
428 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
429 cpl_msg_indent_more();
431 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
432 fors_normalise_flat_exit(
"Too many in input: GRISM_TABLE");
437 "fors.fors_normalise_flat.dispersion", grism_table);
439 if (dispersion <= 0.0)
440 fors_normalise_flat_exit(
"Invalid spectral dispersion value");
443 "fors.fors_normalise_flat.startwavelength", grism_table);
444 if (startwavelength > 1.0)
445 if (startwavelength < 3000.0 || startwavelength > 13000.0)
446 fors_normalise_flat_exit(
"Invalid wavelength");
449 "fors.fors_normalise_flat.endwavelength", grism_table);
450 if (endwavelength > 1.0) {
451 if (endwavelength < 3000.0 || endwavelength > 13000.0)
452 fors_normalise_flat_exit(
"Invalid wavelength");
453 if (startwavelength < 1.0)
454 fors_normalise_flat_exit(
"Invalid wavelength interval");
457 if (startwavelength > 1.0)
458 if (endwavelength - startwavelength <= 0.0)
459 fors_normalise_flat_exit(
"Invalid wavelength interval");
462 "fors.fors_normalise_flat.spa_polydegree", NULL);
464 "fors.fors_normalise_flat.disp_nknots", NULL);
466 "fors.fors_normalise_flat.sradius", NULL);
468 "fors.fors_normalise_flat.dradius", NULL);
470 "fors.fors_normalise_flat.splfit_threshold", NULL);
472 if (sradius < 1 || dradius < 1)
473 fors_normalise_flat_exit(
"Invalid smoothing box radius");
475 cpl_table_delete(grism_table); grism_table = NULL;
477 if (cpl_error_get_code())
478 fors_normalise_flat_exit(
"Failure reading the configuration "
482 cpl_msg_indent_less();
483 cpl_msg_info(recipe,
"Check input set-of-frames:");
484 cpl_msg_indent_more();
486 nflat = mxu = cpl_frameset_count_tags(frameset,
"MASTER_SCREEN_FLAT_MXU");
487 nflat += mos = cpl_frameset_count_tags(frameset,
"MASTER_SCREEN_FLAT_MOS");
488 nflat += lss = cpl_frameset_count_tags(frameset,
"MASTER_SCREEN_FLAT_LSS");
491 fors_normalise_flat_exit(
"Missing input master flat field frame");
494 cpl_msg_error(recipe,
"Too many input flat frames (%d > 1)", nflat);
495 fors_normalise_flat_exit(NULL);
499 master_flat_tag =
"MASTER_SCREEN_FLAT_MXU";
500 master_norm_flat_tag =
"MASTER_NORM_FLAT_MXU";
501 slit_location_tag =
"SLIT_LOCATION_MXU";
502 curv_coeff_tag =
"CURV_COEFF_MXU";
505 master_flat_tag =
"MASTER_SCREEN_FLAT_MOS";
506 master_norm_flat_tag =
"MASTER_NORM_FLAT_MOS";
507 slit_location_tag =
"SLIT_LOCATION_MOS";
508 curv_coeff_tag =
"CURV_COEFF_MOS";
511 master_flat_tag =
"MASTER_SCREEN_FLAT_LSS";
512 master_norm_flat_tag =
"MASTER_NORM_FLAT_LSS";
518 int nslits_out_det = 0;
529 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
531 cpl_table_delete(maskslits); maskslits = NULL;
534 cpl_msg_warning(recipe,
"All MOS slits have the same offset: %.2f\n"
535 "The LSS data reduction strategy is applied!",
539 if (!(lss || treat_as_lss)) {
540 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
541 cpl_msg_error(recipe,
"Missing input: %s", curv_coeff_tag);
542 fors_normalise_flat_exit(NULL);
545 if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
546 cpl_msg_error(recipe,
"Too many in input: %s", curv_coeff_tag);
547 fors_normalise_flat_exit(NULL);
550 if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
551 cpl_msg_error(recipe,
"Missing input: %s", slit_location_tag);
552 fors_normalise_flat_exit(NULL);
555 if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
556 cpl_msg_error(recipe,
"Too many in input: %s", slit_location_tag);
557 fors_normalise_flat_exit(NULL);
562 fors_normalise_flat_exit(
"Input frames are not from the same grism");
565 fors_normalise_flat_exit(
"Input frames are not from the same filter");
568 fors_normalise_flat_exit(
"Input frames are not from the same chip");
577 fors_normalise_flat_exit(
"Cannot load master flat frame header");
579 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
580 if (instrume == NULL)
581 fors_normalise_flat_exit(
"Missing keyword INSTRUME in master "
584 if (instrume[4] ==
'1')
585 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
586 if (instrume[4] ==
'2')
587 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
589 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
591 if (cpl_error_get_code() != CPL_ERROR_NONE)
592 fors_normalise_flat_exit(
"Missing keyword ESO INS GRIS1 WLEN "
593 "in master flat frame header");
595 if (reference < 3000.0)
598 if (reference < 3000.0 || reference > 13000.0) {
599 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
600 "keyword ESO INS GRIS1 WLEN in master flat header",
602 fors_normalise_flat_exit(NULL);
605 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
607 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
609 if (cpl_error_get_code() != CPL_ERROR_NONE)
610 fors_normalise_flat_exit(
"Missing keyword ESO DET WIN1 BINX "
611 "in master flat header");
615 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
616 "working dispersion used is %f A/pixel", rebin,
621 cpl_msg_indent_less();
622 cpl_msg_info(recipe,
"Load input frames...");
623 cpl_msg_indent_more();
626 CPL_TYPE_FLOAT, 0, 0);
627 if (master_flat == NULL)
628 fors_normalise_flat_exit(
"Cannot load master flat field frame");
631 cpl_msg_indent_less();
632 cpl_msg_info(recipe,
"Perform flat field normalisation...");
633 cpl_msg_indent_more();
635 if (lss || treat_as_lss) {
651 smo_flat = mos_lssflat_normalise(master_flat,
653 spa_polyorder, disp_nknots,
656 cpl_image_delete(smo_flat); smo_flat = NULL;
659 header, parlist, recipe, version))
660 fors_normalise_flat_exit(NULL);
662 cpl_propertylist_delete(header); header = NULL;
663 cpl_image_delete(master_flat); master_flat = NULL;
675 fors_normalise_flat_exit(
"Cannot load slits location table");
679 fors_normalise_flat_exit(
"Cannot load spectral curvature table");
681 nx = cpl_image_get_size_x(master_flat);
682 ny = cpl_image_get_size_y(master_flat);
684 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
687 startwavelength, endwavelength,
688 dispersion, 0, coordinate);
690 cpl_image_delete(spatial); spatial = NULL;
692 smo_flat = mos_mosflat_normalise(master_flat, coordinate, slits, polytraces,
693 reference, startwavelength, endwavelength,
694 dispersion, sradius, dradius,
695 spa_polyorder, disp_nknots, splfit_threshold);
697 cpl_image_delete(smo_flat); smo_flat = NULL;
698 cpl_image_delete(coordinate); coordinate = NULL;
699 cpl_table_delete(polytraces); polytraces = NULL;
700 cpl_table_delete(slits); slits = NULL;
703 header, parlist, recipe, version))
704 fors_normalise_flat_exit(NULL);
706 cpl_propertylist_delete(header); header = NULL;
707 cpl_image_delete(master_flat); master_flat = 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.
void fors_print_banner(void)
Issue a banner with the pipeline version.
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_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.
int dfs_get_parameter_int(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe integer parameter value.
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.