37 static int fors_trace_flat_create(cpl_plugin *);
38 static int fors_trace_flat_exec(cpl_plugin *);
39 static int fors_trace_flat_destroy(cpl_plugin *);
40 static int fors_trace_flat(cpl_parameterlist *, cpl_frameset *);
42 static char fors_trace_flat_description[] =
43 "This recipe is used to trace the edges of MOS/MXU flat field slit spectra\n"
44 "and determine the spectral curvature solution. The input master flat field\n"
45 "image, product of the recipe fors_flat, is expected to be oriented with\n"
46 "horizontal dispersion direction and red wavelengths on the right side.\n"
47 "The input slits location table should be the product of the recipe\n"
48 "fors_detect_spectra.\n"
50 "The input master flat image is shifted one pixel down and is subtracted\n"
51 "from the original image. The result is a vertical gradient map. Next,\n"
52 "the negative values are forced positive, to obtain an absolute gradient\n"
53 "map. The map is passed with a horizontal median filter, and after that\n"
54 "the gradient peaks are traced starting from the slits positions listed\n"
55 "in the input slits location table. The number of pixels to the left and\n"
56 "to the right of the reference pixel is trivially derived from the specified\n"
57 "spectral range and spectral dispersion.\n"
59 "The output spectral curvature table contains the coefficients of the\n"
60 "polynomial fitting of the found traces, while the output trace table\n"
61 "contains the traced spectral edges positions in CCD (Y) coordinates for\n"
62 "each spectrum, and their comparison with their modeling. A spatial map\n"
63 "is also created, where to each CCD pixel is assigned the value of the\n"
64 "spatial coordinate along the slit (in pixel). For more details please\n"
65 "refer to the FORS Pipeline User's Manual.\n"
67 "Note that specifying an input GRISM_TABLE will set some of the recipe\n"
68 "configuration parameters to default values valid for a particular grism.\n"
69 "Again, see the pipeline manual for more details.\n"
71 "In the table below the MXU acronym can be alternatively read as MOS.\n\n"
73 " DO category: Type: Explanation: Required:\n"
74 " MASTER_SCREEN_FLAT_MXU Calib Master flat frame Y\n"
75 " SLIT_LOCATION_DETECT_MXU Calib Slits location Y\n"
76 " GRISM_TABLE Calib Grism table .\n\n"
78 " DO category: Data type: Explanation:\n"
79 " CURV_TRACES_MXU FITS table Flat field tracings\n"
80 " CURV_COEFF_MXU FITS table Spectral curvature table\n"
81 " SPATIAL_MAP_MXU FITS image Map of spatial coordinate\n\n";
83 #define fors_trace_flat_exit(message) \
85 if (message) cpl_msg_error(recipe, message); \
86 cpl_image_delete(master_flat); \
87 cpl_image_delete(spatial); \
88 cpl_image_delete(coordinate); \
89 cpl_table_delete(grism_table); \
90 cpl_table_delete(maskslits); \
91 cpl_table_delete(slits); \
92 cpl_table_delete(traces); \
93 cpl_table_delete(polytraces); \
94 cpl_propertylist_delete(header); \
95 cpl_msg_indent_less(); \
99 #define fors_trace_flat_exit_memcheck(message) \
101 if (message) cpl_msg_info(recipe, message); \
102 printf("free master_flat (%p)\n", master_flat); \
103 cpl_image_delete(master_flat); \
104 printf("free spatial (%p)\n", spatial); \
105 cpl_image_delete(spatial); \
106 printf("free coordinate (%p)\n", coordinate); \
107 cpl_image_delete(coordinate); \
108 printf("free grism_table (%p)\n", grism_table); \
109 cpl_table_delete(grism_table); \
110 printf("free maskslits (%p)\n", maskslits); \
111 cpl_table_delete(maskslits); \
112 printf("free slits (%p)\n", slits); \
113 cpl_table_delete(slits); \
114 printf("free traces (%p)\n", traces); \
115 cpl_table_delete(traces); \
116 printf("free polytraces (%p)\n", polytraces); \
117 cpl_table_delete(polytraces); \
118 printf("free header (%p)\n", header); \
119 cpl_propertylist_delete(header); \
120 cpl_msg_indent_less(); \
138 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe );
139 cpl_plugin *plugin = &recipe->interface;
141 cpl_plugin_init(plugin,
144 CPL_PLUGIN_TYPE_RECIPE,
146 "Determine spectral curvature model",
147 fors_trace_flat_description,
150 "This file is currently part of the FORS Instrument Pipeline\n"
151 "Copyright (C) 2002-2010 European Southern Observatory\n\n"
152 "This program is free software; you can redistribute it and/or modify\n"
153 "it under the terms of the GNU General Public License as published by\n"
154 "the Free Software Foundation; either version 2 of the License, or\n"
155 "(at your option) any later version.\n\n"
156 "This program is distributed in the hope that it will be useful,\n"
157 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
158 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
159 "GNU General Public License for more details.\n\n"
160 "You should have received a copy of the GNU General Public License\n"
161 "along with this program; if not, write to the Free Software Foundation,\n"
162 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
163 fors_trace_flat_create,
164 fors_trace_flat_exec,
165 fors_trace_flat_destroy);
167 cpl_pluginlist_append(list, plugin);
183 static int fors_trace_flat_create(cpl_plugin *plugin)
192 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
193 recipe = (cpl_recipe *)plugin;
201 recipe->parameters = cpl_parameterlist_new();
207 p = cpl_parameter_new_value(
"fors.fors_trace_flat.dispersion",
209 "Expected spectral dispersion (Angstrom/pixel)",
210 "fors.fors_trace_flat",
212 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dispersion");
213 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
214 cpl_parameterlist_append(recipe->parameters, p);
220 p = cpl_parameter_new_value(
"fors.fors_trace_flat.startwavelength",
222 "Start wavelength in spectral extraction",
223 "fors.fors_trace_flat",
225 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"startwavelength");
226 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
227 cpl_parameterlist_append(recipe->parameters, p);
233 p = cpl_parameter_new_value(
"fors.fors_trace_flat.endwavelength",
235 "End wavelength in spectral extraction",
236 "fors.fors_trace_flat",
238 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"endwavelength");
239 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
240 cpl_parameterlist_append(recipe->parameters, p);
246 p = cpl_parameter_new_value(
"fors.fors_trace_flat.cdegree",
248 "Degree of spectral curvature polynomial",
249 "fors.fors_trace_flat",
251 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cdegree");
252 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
253 cpl_parameterlist_append(recipe->parameters, p);
259 p = cpl_parameter_new_value(
"fors.fors_trace_flat.cmode",
261 "Interpolation mode of curvature solution "
262 "applicable to MOS-like data (0 = no "
263 "interpolation, 1 = fill gaps, 2 = global "
265 "fors.fors_trace_flat",
267 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"cmode");
268 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
269 cpl_parameterlist_append(recipe->parameters, p);
283 static int fors_trace_flat_exec(cpl_plugin *plugin)
287 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
288 recipe = (cpl_recipe *)plugin;
292 return fors_trace_flat(recipe->parameters, recipe->frames);
304 static int fors_trace_flat_destroy(cpl_plugin *plugin)
308 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
309 recipe = (cpl_recipe *)plugin;
313 cpl_parameterlist_delete(recipe->parameters);
328 static int fors_trace_flat(cpl_parameterlist *parlist,
329 cpl_frameset *frameset)
332 const char *recipe =
"fors_trace_flat";
340 double startwavelength;
341 double endwavelength;
349 cpl_image *master_flat = NULL;
350 cpl_image *coordinate = NULL;
351 cpl_image *spatial = NULL;
352 cpl_table *grism_table = NULL;
353 cpl_table *maskslits = NULL;
354 cpl_table *slits = NULL;
355 cpl_table *traces = NULL;
356 cpl_table *polytraces = NULL;
357 cpl_propertylist *header = NULL;
364 const char *master_flat_tag;
365 const char *spatial_map_tag;
366 const char *slit_detect_tag;
367 const char *slit_location_tag;
368 const char *curv_traces_tag;
369 const char *curv_coeff_tag;
380 int nslits_out_det = 0;
382 char *instrume = NULL;
385 cpl_msg_set_indentation(2);
391 cpl_msg_info(recipe,
"Recipe %s configuration parameters:", recipe);
392 cpl_msg_indent_more();
394 if (cpl_frameset_count_tags(frameset,
"GRISM_TABLE") > 1)
395 fors_trace_flat_exit(
"Too many in input: GRISM_TABLE");
400 "fors.fors_trace_flat.dispersion", grism_table);
402 if (dispersion <= 0.0)
403 fors_trace_flat_exit(
"Invalid spectral dispersion value");
406 "fors.fors_trace_flat.startwavelength", grism_table);
407 if (startwavelength > 1.0)
408 if (startwavelength < 3000.0 || startwavelength > 13000.0)
409 fors_trace_flat_exit(
"Invalid wavelength");
412 "fors.fors_trace_flat.endwavelength", grism_table);
413 if (endwavelength > 1.0) {
414 if (endwavelength < 3000.0 || endwavelength > 13000.0)
415 fors_trace_flat_exit(
"Invalid wavelength");
416 if (startwavelength < 1.0)
417 fors_trace_flat_exit(
"Invalid wavelength interval");
420 if (startwavelength > 1.0)
421 if (endwavelength - startwavelength <= 0.0)
422 fors_trace_flat_exit(
"Invalid wavelength interval");
425 "fors.fors_trace_flat.cdegree", grism_table);
428 fors_trace_flat_exit(
"Invalid polynomial degree");
431 fors_trace_flat_exit(
"Max allowed polynomial degree is 5");
435 if (cmode < 0 || cmode > 2)
436 fors_trace_flat_exit(
"Invalid curvature solution interpolation mode");
438 cpl_table_delete(grism_table); grism_table = NULL;
440 if (cpl_error_get_code())
441 fors_trace_flat_exit(
"Failure reading the configuration parameters");
444 cpl_msg_indent_less();
445 cpl_msg_info(recipe,
"Check input set-of-frames:");
446 cpl_msg_indent_more();
448 nflat = flat_mxu = cpl_frameset_count_tags(frameset,
449 "MASTER_SCREEN_FLAT_MXU");
450 nflat += flat_mos = cpl_frameset_count_tags(frameset,
451 "MASTER_SCREEN_FLAT_MOS");
452 nflat += flat_lss = cpl_frameset_count_tags(frameset,
453 "MASTER_SCREEN_FLAT_LSS");
456 fors_trace_flat_exit(
"Missing input master flat field frame");
459 cpl_msg_error(recipe,
"Too many input flat frames (%d > 1)", nflat);
460 fors_trace_flat_exit(NULL);
466 master_flat_tag =
"MASTER_SCREEN_FLAT_MXU";
467 slit_detect_tag =
"SLIT_LOCATION_DETECT_MXU";
468 slit_location_tag =
"SLIT_LOCATION_MXU";
469 curv_traces_tag =
"CURV_TRACES_MXU";
470 curv_coeff_tag =
"CURV_COEFF_MXU";
471 spatial_map_tag =
"SPATIAL_MAP_MXU";
475 master_flat_tag =
"MASTER_SCREEN_FLAT_MOS";
476 slit_detect_tag =
"SLIT_LOCATION_DETECT_MOS";
477 slit_location_tag =
"SLIT_LOCATION_MOS";
478 curv_traces_tag =
"CURV_TRACES_MOS";
479 curv_coeff_tag =
"CURV_COEFF_MOS";
480 spatial_map_tag =
"SPATIAL_MAP_MOS";
483 fors_trace_flat_exit(
"LSS spectra are not traceable: use this recipe "
484 "just for MOS/MXU data.");
487 if (cpl_frameset_count_tags(frameset, slit_detect_tag) == 0) {
488 cpl_msg_error(recipe,
"Missing required input: %s", slit_detect_tag);
489 fors_trace_flat_exit(NULL);
492 if (cpl_frameset_count_tags(frameset, slit_detect_tag) > 1) {
493 cpl_msg_error(recipe,
"Too many in input: %s", slit_detect_tag);
494 fors_trace_flat_exit(NULL);
498 fors_trace_flat_exit(
"Input frames are not from the same grism");
501 fors_trace_flat_exit(
"Input frames are not from the same filter");
504 fors_trace_flat_exit(
"Input frames are not from the same chip");
515 fors_trace_flat_exit(
"Cannot load master flat frame header");
517 instrume = (
char *)cpl_propertylist_get_string(header,
"INSTRUME");
518 if (instrume == NULL)
519 fors_trace_flat_exit(
"Missing keyword INSTRUME in master flat header");
521 if (instrume[4] ==
'1')
522 snprintf(version, 80,
"%s/%s",
"fors1", VERSION);
523 if (instrume[4] ==
'2')
524 snprintf(version, 80,
"%s/%s",
"fors2", VERSION);
526 reference = cpl_propertylist_get_double(header,
"ESO INS GRIS1 WLEN");
528 if (cpl_error_get_code() != CPL_ERROR_NONE)
529 fors_trace_flat_exit(
"Missing keyword ESO INS GRIS1 WLEN "
530 "in master flat frame header");
532 if (reference < 3000.0)
535 if (reference < 3000.0 || reference > 13000.0) {
536 cpl_msg_error(recipe,
"Invalid central wavelength %.2f read from "
537 "keyword ESO INS GRIS1 WLEN in master flat header",
539 fors_trace_flat_exit(NULL);
542 cpl_msg_info(recipe,
"The central wavelength is: %.2f", reference);
544 rebin = cpl_propertylist_get_int(header,
"ESO DET WIN1 BINX");
546 if (cpl_error_get_code() != CPL_ERROR_NONE)
547 fors_trace_flat_exit(
"Missing keyword ESO DET WIN1 BINX "
548 "in master flat header");
552 cpl_msg_warning(recipe,
"The rebin factor is %d, and therefore the "
553 "working dispersion used is %f A/pixel", rebin,
567 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
570 cpl_msg_error(recipe,
"All slits have the same offset: %.2f mm\n"
571 "Spectra are not traceable: the LSS data reduction\n"
572 "strategy must be applied.", mxpos);
573 fors_trace_flat_exit(NULL);
576 cpl_table_delete(maskslits); maskslits = NULL;
579 cpl_msg_indent_less();
580 cpl_msg_info(recipe,
"Load input frames...");
581 cpl_msg_indent_more();
584 CPL_TYPE_FLOAT, 0, 0);
585 if (master_flat == NULL)
586 fors_trace_flat_exit(
"Cannot load master flat field frame");
590 fors_trace_flat_exit(
"Cannot load slits location table");
593 cpl_msg_indent_less();
594 cpl_msg_info(recipe,
"Determining spectral curvature...");
595 cpl_msg_indent_more();
597 cpl_msg_info(recipe,
"Tracing master flat field spectra edges...");
599 startwavelength, endwavelength, dispersion);
602 fors_trace_flat_exit(
"Tracing failure");
604 cpl_msg_info(recipe,
"Fitting flat field spectra edges...");
608 fors_trace_flat_exit(
"Trace fitting failure");
611 cpl_msg_info(recipe,
"Computing global spectral curvature model...");
615 if (
dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist,
617 fors_trace_flat_exit(NULL);
619 cpl_table_delete(traces); traces = NULL;
621 nx = cpl_image_get_size_x(master_flat);
622 ny = cpl_image_get_size_y(master_flat);
623 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
627 startwavelength, endwavelength,
628 dispersion, 0, coordinate);
630 cpl_image_delete(master_flat); master_flat = NULL;
631 cpl_image_delete(spatial); spatial = NULL;
634 parlist, recipe, version))
635 fors_trace_flat_exit(NULL);
637 cpl_image_delete(coordinate); coordinate = NULL;
638 cpl_propertylist_delete(header); header = NULL;
641 parlist, recipe, version))
642 fors_trace_flat_exit(NULL);
644 cpl_table_delete(slits); slits = NULL;
647 parlist, recipe, version))
648 fors_trace_flat_exit(NULL);
650 cpl_table_delete(polytraces); polytraces = 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.
cpl_table * mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
Fit spectral traces.
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces, int mode)
Recompute tracing coefficients globally.
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_table * mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference, double blue, double red, double dispersion)
Trace flat field spectra.
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.
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.