FORS Pipeline Reference Manual  5.0.9
fors_align_sky.c
1 /* $Id: fors_align_sky.c,v 1.8 2013-08-14 16:07:47 cgarcia Exp $
2  *
3  * This file is part of the FORS Data Reduction Pipeline
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013-08-14 16:07:47 $
24  * $Revision: 1.8 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <math.h>
33 #include <cpl.h>
34 #include <moses.h>
35 #include <fors_dfs.h>
36 
37 static int fors_align_sky_create(cpl_plugin *);
38 static int fors_align_sky_exec(cpl_plugin *);
39 static int fors_align_sky_destroy(cpl_plugin *);
40 static int fors_align_sky(cpl_parameterlist *, cpl_frameset *);
41 
42 static char fors_align_sky_description[] =
43 "This recipe is used to align the wavelength solution based on the arc\n"
44 "lamp exposure on a set of sky lines observed on a scientific exposure.\n"
45 "The input rectified frames are produced by the recipe fors_extract_slits.\n"
46 "An input catalog of sky lines can be specified, otherwise an internal one\n"
47 "is used.\n"
48 "\n"
49 "This recipe should be applied to multi-slit MOS/MXU data: for LSS or\n"
50 "long-slit like data (MOS/MXU with all slits at the same offset) use recipe\n"
51 "fors_align_sky_lss instead. Please refer to the FORS Pipeline User's Manual\n"
52 "for more details.\n"
53 "\n"
54 "In the table below the MXU acronym can be alternatively read as MOS, and\n"
55 "SCI as STD.\n\n"
56 "Input files:\n\n"
57 " DO category: Type: Explanation: Required:\n"
58 " RECTIFIED_ALL_SCI_MXU\n"
59 " or RECTIFIED_SKY_SCI_MXU Calib Frame with sky lines Y\n"
60 " SPATIAL_MAP_MXU Calib Spatial coordinate map Y\n"
61 " CURV_COEFF_MXU Calib Spectral curvature Y\n"
62 " SLIT_LOCATION_MXU Calib Slit location on CCD Y\n"
63 " DISP_COEFF_MXU Calib Dispersion solution Y\n"
64 " MASTER_SKYLINECAT Calib Catalog of sky lines .\n"
65 " GRISM_TABLE Calib Grism table .\n\n"
66 "Output files:\n\n"
67 " DO category: Data type: Explanation:\n"
68 " SKY_SHIFTS_SLIT_SCI_MXU FITS table Observed sky lines offsets\n"
69 " WAVELENGTH_MAP_SCI_MXU FITS image Wavelength mapped on CCD\n"
70 " DISP_COEFF_SCI_MXU FITS image Upgraded dispersion solution\n\n";
71 
72 #define fors_align_sky_exit(message) \
73 { \
74 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
75 cpl_image_delete(wavemap); \
76 cpl_image_delete(coordinate); \
77 cpl_image_delete(rainbow); \
78 cpl_image_delete(smapped); \
79 cpl_table_delete(grism_table); \
80 cpl_table_delete(maskslits); \
81 cpl_table_delete(wavelengths); \
82 cpl_table_delete(offsets); \
83 cpl_table_delete(slits); \
84 cpl_table_delete(polytraces); \
85 cpl_table_delete(idscoeff); \
86 cpl_vector_delete(lines); \
87 cpl_propertylist_delete(header); \
88 cpl_msg_indent_less(); \
89 return -1; \
90 }
91 
92 #define fors_align_sky_exit_memcheck(message) \
93 { \
94 if ((const char *)message != NULL) cpl_msg_info(recipe, message); \
95 printf("free wavemap (%p)\n", wavemap); \
96 cpl_image_delete(wavemap); \
97 printf("free coordinate (%p)\n", coordinate); \
98 cpl_image_delete(coordinate); \
99 printf("free rainbow (%p)\n", rainbow); \
100 cpl_image_delete(rainbow); \
101 printf("free smapped (%p)\n", smapped); \
102 cpl_image_delete(smapped); \
103 printf("free grism_table (%p)\n", grism_table); \
104 cpl_table_delete(grism_table); \
105 printf("free maskslits (%p)\n", maskslits); \
106 cpl_table_delete(maskslits); \
107 printf("free wavelengths (%p)\n", wavelengths); \
108 cpl_table_delete(wavelengths); \
109 printf("free offsets (%p)\n", offsets); \
110 cpl_table_delete(offsets); \
111 printf("free idscoeff (%p)\n", idscoeff); \
112 cpl_table_delete(idscoeff); \
113 printf("free slits (%p)\n", slits); \
114 cpl_table_delete(slits); \
115 printf("free polytraces (%p)\n", polytraces); \
116 cpl_table_delete(polytraces); \
117 printf("free lines (%p)\n", lines); \
118 cpl_vector_delete(lines); \
119 printf("free header (%p)\n", header); \
120 cpl_propertylist_delete(header); \
121 cpl_msg_indent_less(); \
122 return 0; \
123 }
124 
125 
137 int cpl_plugin_get_info(cpl_pluginlist *list)
138 {
139  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
140  cpl_plugin *plugin = &recipe->interface;
141 
142  cpl_plugin_init(plugin,
143  CPL_PLUGIN_API,
144  FORS_BINARY_VERSION,
145  CPL_PLUGIN_TYPE_RECIPE,
146  "fors_align_sky",
147  "Upgrade wavelength solution using sky lines",
148  fors_align_sky_description,
149  "Carlo Izzo",
150  PACKAGE_BUGREPORT,
151  "This file is currently part of the FORS Instrument Pipeline\n"
152  "Copyright (C) 2002-2010 European Southern Observatory\n\n"
153  "This program is free software; you can redistribute it and/or modify\n"
154  "it under the terms of the GNU General Public License as published by\n"
155  "the Free Software Foundation; either version 2 of the License, or\n"
156  "(at your option) any later version.\n\n"
157  "This program is distributed in the hope that it will be useful,\n"
158  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
159  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
160  "GNU General Public License for more details.\n\n"
161  "You should have received a copy of the GNU General Public License\n"
162  "along with this program; if not, write to the Free Software Foundation,\n"
163  "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
164  fors_align_sky_create,
165  fors_align_sky_exec,
166  fors_align_sky_destroy);
167 
168  cpl_pluginlist_append(list, plugin);
169 
170  return 0;
171 }
172 
173 
184 static int fors_align_sky_create(cpl_plugin *plugin)
185 {
186  cpl_recipe *recipe;
187  cpl_parameter *p;
188 
189  /*
190  * Check that the plugin is part of a valid recipe
191  */
192 
193  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
194  recipe = (cpl_recipe *)plugin;
195  else
196  return -1;
197 
198  /*
199  * Create the (empty) parameters list in the cpl_recipe object
200  */
201 
202  recipe->parameters = cpl_parameterlist_new();
203 
204  /*
205  * Dispersion
206  */
207 
208  p = cpl_parameter_new_value("fors.fors_align_sky.dispersion",
209  CPL_TYPE_DOUBLE,
210  "Expected spectral dispersion (Angstrom/pixel)",
211  "fors.fors_align_sky",
212  0.0);
213  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
214  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
215  cpl_parameterlist_append(recipe->parameters, p);
216 
217  /*
218  * Start wavelength for spectral extraction
219  */
220 
221  p = cpl_parameter_new_value("fors.fors_align_sky.startwavelength",
222  CPL_TYPE_DOUBLE,
223  "Start wavelength in spectral extraction",
224  "fors.fors_align_sky",
225  0.0);
226  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
227  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
228  cpl_parameterlist_append(recipe->parameters, p);
229 
230  /*
231  * End wavelength for spectral extraction
232  */
233 
234  p = cpl_parameter_new_value("fors.fors_align_sky.endwavelength",
235  CPL_TYPE_DOUBLE,
236  "End wavelength in spectral extraction",
237  "fors.fors_align_sky",
238  0.0);
239  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
240  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
241  cpl_parameterlist_append(recipe->parameters, p);
242 
243  /*
244  * Sky lines alignment
245  */
246 
247  p = cpl_parameter_new_value("fors.fors_align_sky.skyalign",
248  CPL_TYPE_INT,
249  "Polynomial order for sky lines alignment",
250  "fors.fors_align_sky",
251  0);
252  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
253  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
254  cpl_parameterlist_append(recipe->parameters, p);
255 
256  /*
257  * Line catalog table column containing the sky reference wavelengths
258  */
259 
260  p = cpl_parameter_new_value("fors.fors_align_sky.wcolumn",
261  CPL_TYPE_STRING,
262  "Name of sky line catalog table column "
263  "with wavelengths",
264  "fors.fors_align_sky",
265  "WLEN");
266  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
267  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
268  cpl_parameterlist_append(recipe->parameters, p);
269 
270  return 0;
271 }
272 
273 
282 static int fors_align_sky_exec(cpl_plugin *plugin)
283 {
284  cpl_recipe *recipe;
285 
286  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
287  recipe = (cpl_recipe *)plugin;
288  else
289  return -1;
290 
291  return fors_align_sky(recipe->parameters, recipe->frames);
292 }
293 
294 
303 static int fors_align_sky_destroy(cpl_plugin *plugin)
304 {
305  cpl_recipe *recipe;
306 
307  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
308  recipe = (cpl_recipe *)plugin;
309  else
310  return -1;
311 
312  cpl_parameterlist_delete(recipe->parameters);
313 
314  return 0;
315 }
316 
317 
327 static int fors_align_sky(cpl_parameterlist *parlist,
328  cpl_frameset *frameset)
329 {
330 
331  const char *recipe = "fors_align_sky";
332 
333 
334  /*
335  * Input parameters
336  */
337 
338  double dispersion;
339  double startwavelength;
340  double endwavelength;
341  int skyalign;
342  const char *wcolumn;
343 
344  /*
345  * CPL objects
346  */
347 
348  cpl_image *rainbow = NULL;
349  cpl_image *wavemap = NULL;
350  cpl_image *smapped = NULL;
351  cpl_image *coordinate = NULL;
352  cpl_table *grism_table = NULL;
353  cpl_table *wavelengths = NULL;
354  cpl_table *slits = NULL;
355  cpl_table *idscoeff = NULL;
356  cpl_table *polytraces = NULL;
357  cpl_table *maskslits = NULL;
358  cpl_table *offsets = NULL;
359  cpl_vector *lines = NULL;
360  cpl_propertylist *header = NULL;
361 
362  /*
363  * Auxiliary variables
364  */
365 
366  char version[80];
367  const char *slit_location_tag;
368  const char *curv_coeff_tag;
369  const char *rectified_tag;
370  const char *wavemap_tag;
371  const char *shifts_tag;
372  const char *disp_ali_tag;
373  const char *disp_coeff_tag;
374  const char *spatial_map_tag;
375  int nframes;
376  int rebin;
377  int nlines;
378  int nx;
379  int highres;
380  int treat_as_lss;
381  int i;
382  double reference;
383  double mxpos;
384  double *line;
385  int mxu, mos;
386  int rec_scia;
387  int rec_stda;
388  int rec_scis;
389  int rec_stds;
390  int nslits_out_det = 0;
391 
392 
393  char *instrume = NULL;
394 
395 
396  cpl_msg_set_indentation(2);
397 
398 
399  /*
400  * Get configuration parameters
401  */
402 
403  cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
404  cpl_msg_indent_more();
405 
406  if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
407  fors_align_sky_exit("Too many in input: GRISM_TABLE");
408 
409  grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
410 
411  dispersion = dfs_get_parameter_double(parlist,
412  "fors.fors_align_sky.dispersion", grism_table);
413 
414  if (dispersion <= 0.0)
415  fors_align_sky_exit("Invalid spectral dispersion value");
416 
417  startwavelength = dfs_get_parameter_double(parlist,
418  "fors.fors_align_sky.startwavelength", grism_table);
419  if (startwavelength > 1.0)
420  if (startwavelength < 3000.0 || startwavelength > 13000.0)
421  fors_align_sky_exit("Invalid wavelength");
422 
423  endwavelength = dfs_get_parameter_double(parlist,
424  "fors.fors_align_sky.endwavelength", grism_table);
425  if (endwavelength > 1.0) {
426  if (endwavelength < 3000.0 || endwavelength > 13000.0)
427  fors_align_sky_exit("Invalid wavelength");
428  if (startwavelength < 1.0)
429  fors_align_sky_exit("Invalid wavelength interval");
430  }
431 
432  if (startwavelength > 1.0)
433  if (endwavelength - startwavelength <= 0.0)
434  fors_align_sky_exit("Invalid wavelength interval");
435 
436  skyalign = dfs_get_parameter_int(parlist,
437  "fors.fors_align_sky.skyalign", NULL);
438 
439  if (skyalign < 0)
440  fors_align_sky_exit("Invalid polynomial degree");
441  if (skyalign > 2)
442  fors_align_sky_exit("Max polynomial degree for sky alignment is 2");
443 
444  wcolumn = dfs_get_parameter_string(parlist,
445  "fors.fors_align_sky.wcolumn", NULL);
446 
447  cpl_table_delete(grism_table); grism_table = NULL;
448 
449  if (cpl_error_get_code())
450  fors_align_sky_exit("Failure reading the configuration parameters");
451 
452 
453  cpl_msg_indent_less();
454  cpl_msg_info(recipe, "Check input set-of-frames:");
455  cpl_msg_indent_more();
456 
457  mxu = cpl_frameset_count_tags(frameset, "SPATIAL_MAP_MXU");
458  mos = cpl_frameset_count_tags(frameset, "SPATIAL_MAP_MOS");
459 
460  nframes = mos + mxu;
461 
462  if (nframes == 0) {
463  fors_align_sky_exit("Missing input spatial map");
464  }
465  if (nframes > 1) {
466  cpl_msg_error(recipe,
467  "Too many input spatial maps (%d > 1)", nframes);
468  fors_align_sky_exit(NULL);
469  }
470 
471  if (mxu) {
472  rec_scia = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_SCI_MXU");
473  rec_stda = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_STD_MXU");
474  rec_scis = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_SCI_MXU");
475  rec_stds = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_STD_MXU");
476  }
477  else {
478  rec_scia = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_SCI_MOS");
479  rec_stda = cpl_frameset_count_tags(frameset, "RECTIFIED_ALL_STD_MOS");
480  rec_scis = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_SCI_MOS");
481  rec_stds = cpl_frameset_count_tags(frameset, "RECTIFIED_SKY_STD_MOS");
482  }
483 
484  nframes = rec_scia + rec_stda + rec_scis + rec_stds;
485 
486  if (nframes == 0) {
487  fors_align_sky_exit("Missing input rectified scientific spectra");
488  }
489  if (nframes > 1) {
490  cpl_msg_error(recipe,
491  "Too many input rectified scientific spectra (%d > 1)",
492  nframes);
493  fors_align_sky_exit(NULL);
494  }
495 
496  if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
497  fors_align_sky_exit("Too many in input: MASTER_SKYLINECAT");
498 
499  if (rec_scia) {
500  if (mxu) {
501  rectified_tag = "RECTIFIED_ALL_SCI_MXU";
502  wavemap_tag = "WAVELENGTH_MAP_SCI_MXU";
503  shifts_tag = "SKY_SHIFTS_SLIT_SCI_MXU";
504  disp_ali_tag = "DISP_COEFF_SCI_MXU";
505  }
506  else {
507  rectified_tag = "RECTIFIED_ALL_SCI_MOS";
508  wavemap_tag = "WAVELENGTH_MAP_SCI_MOS";
509  shifts_tag = "SKY_SHIFTS_SLIT_SCI_MOS";
510  disp_ali_tag = "DISP_COEFF_SCI_MOS";
511  }
512  }
513  else if (rec_stda) {
514  if (mxu) {
515  rectified_tag = "RECTIFIED_ALL_STD_MXU";
516  wavemap_tag = "WAVELENGTH_MAP_STD_MXU";
517  shifts_tag = "SKY_SHIFTS_SLIT_STD_MXU";
518  disp_ali_tag = "DISP_COEFF_STD_MXU";
519  }
520  else {
521  rectified_tag = "RECTIFIED_ALL_STD_MOS";
522  wavemap_tag = "WAVELENGTH_MAP_STD_MOS";
523  shifts_tag = "SKY_SHIFTS_SLIT_STD_MOS";
524  disp_ali_tag = "DISP_COEFF_STD_MOS";
525  }
526  }
527  else if (rec_scis) {
528  if (mxu) {
529  rectified_tag = "RECTIFIED_SKY_SCI_MXU";
530  wavemap_tag = "WAVELENGTH_MAP_SCI_MXU";
531  shifts_tag = "SKY_SHIFTS_SLIT_SCI_MXU";
532  disp_ali_tag = "DISP_COEFF_SCI_MXU";
533  }
534  else {
535  rectified_tag = "RECTIFIED_SKY_SCI_MOS";
536  wavemap_tag = "WAVELENGTH_MAP_SCI_MOS";
537  shifts_tag = "SKY_SHIFTS_SLIT_SCI_MOS";
538  disp_ali_tag = "DISP_COEFF_SCI_MOS";
539  }
540  }
541  else if (rec_stds) {
542  if (mxu) {
543  rectified_tag = "RECTIFIED_SKY_STD_MXU";
544  wavemap_tag = "WAVELENGTH_MAP_STD_MXU";
545  shifts_tag = "SKY_SHIFTS_SLIT_STD_MXU";
546  disp_ali_tag = "DISP_COEFF_STD_MXU";
547  }
548  else {
549  rectified_tag = "RECTIFIED_SKY_STD_MOS";
550  wavemap_tag = "WAVELENGTH_MAP_STD_MOS";
551  shifts_tag = "SKY_SHIFTS_SLIT_STD_MOS";
552  disp_ali_tag = "DISP_COEFF_STD_MOS";
553  }
554  }
555 
556 
557  if (mxu) {
558  disp_coeff_tag = "DISP_COEFF_MXU";
559  curv_coeff_tag = "CURV_COEFF_MXU";
560  slit_location_tag = "SLIT_LOCATION_MXU";
561  spatial_map_tag = "SPATIAL_MAP_MXU";
562  }
563  else {
564  disp_coeff_tag = "DISP_COEFF_MOS";
565  curv_coeff_tag = "CURV_COEFF_MOS";
566  slit_location_tag = "SLIT_LOCATION_MOS";
567  spatial_map_tag = "SPATIAL_MAP_MOS";
568  }
569 
570  nframes = cpl_frameset_count_tags(frameset, disp_coeff_tag);
571 
572  if (nframes == 0) {
573  cpl_msg_error(recipe, "Missing input %s\n", disp_coeff_tag);
574  fors_align_sky_exit(NULL);
575  }
576  if (nframes > 1) {
577  cpl_msg_error(recipe,
578  "Too many input %s (%d > 1)", disp_coeff_tag, nframes);
579  fors_align_sky_exit(NULL);
580  }
581 
582  nframes = cpl_frameset_count_tags(frameset, curv_coeff_tag);
583 
584  if (nframes == 0) {
585  cpl_msg_error(recipe, "Missing input %s\n", curv_coeff_tag);
586  fors_align_sky_exit(NULL);
587  }
588  if (nframes > 1) {
589  cpl_msg_error(recipe,
590  "Too many input %s (%d > 1)", curv_coeff_tag, nframes);
591  fors_align_sky_exit(NULL);
592  }
593 
594  nframes = cpl_frameset_count_tags(frameset, spatial_map_tag);
595 
596  if (nframes == 0) {
597  cpl_msg_error(recipe, "Missing input %s\n", spatial_map_tag);
598  fors_align_sky_exit(NULL);
599  }
600  if (nframes > 1) {
601  cpl_msg_error(recipe,
602  "Too many input %s (%d > 1)", spatial_map_tag, nframes);
603  fors_align_sky_exit(NULL);
604  }
605 
606 
607  header = dfs_load_header(frameset, spatial_map_tag, 0);
608 
609  if (header == NULL)
610  fors_align_sky_exit("Cannot load spatial map header");
611 
612  if (mos)
613  maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
614  else
615  maskslits = mos_load_slits_fors_mxu(header);
616 
617  /*
618  * Check if all slits have the same X offset: in such case, abort!
619  */
620 
621  treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
622 
623  cpl_table_delete(maskslits); maskslits = NULL;
624 
625  if (treat_as_lss) {
626  cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n"
627  "The LSS data reduction strategy must be applied. "
628  "Please use recipe fors_align_sky_lss.", mxpos);
629  fors_align_sky_exit(NULL);
630  }
631 
632  if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
633  cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
634 
635  if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
636  cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
637 
638  if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
639  cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
640 
641 
642  /*
643  * Get the reference wavelength and the rebin factor along the
644  * dispersion direction from the reference frame
645  */
646 
647  instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
648  if (instrume == NULL)
649  fors_align_sky_exit("Missing keyword INSTRUME in reference frame "
650  "header");
651 
652  if (instrume[4] == '1')
653  snprintf(version, 80, "%s/%s", "fors1", VERSION);
654  if (instrume[4] == '2')
655  snprintf(version, 80, "%s/%s", "fors2", VERSION);
656 
657  reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
658 
659  if (cpl_error_get_code() != CPL_ERROR_NONE)
660  fors_align_sky_exit("Missing keyword ESO INS GRIS1 WLEN "
661  "in reference frame header");
662 
663  if (reference < 3000.0) /* Perhaps in nanometers... */
664  reference *= 10;
665 
666  if (reference < 3000.0 || reference > 13000.0) {
667  cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
668  "keyword ESO INS GRIS1 WLEN in reference frame header",
669  reference);
670  fors_align_sky_exit(NULL);
671  }
672 
673  cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
674 
675  rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
676 
677  if (cpl_error_get_code() != CPL_ERROR_NONE)
678  fors_align_sky_exit("Missing keyword ESO DET WIN1 BINX "
679  "in reference frame header");
680 
681  if (rebin != 1) {
682  dispersion *= rebin;
683  cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
684  "working dispersion used is %f A/pixel", rebin,
685  dispersion);
686  }
687 
688  cpl_msg_indent_less();
689  cpl_msg_info(recipe, "Load input frames...");
690  cpl_msg_indent_more();
691 
692  coordinate = dfs_load_image(frameset, spatial_map_tag,
693  CPL_TYPE_FLOAT, 0, 0);
694  if (coordinate == NULL)
695  fors_align_sky_exit("Cannot load input reference frame");
696 
697  slits = dfs_load_table(frameset, slit_location_tag, 1);
698  if (slits == NULL)
699  fors_align_sky_exit("Cannot load slits location table");
700 
701  polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
702  if (polytraces == NULL)
703  fors_align_sky_exit("Cannot load spectral curvature table");
704 
705  idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
706  if (idscoeff == NULL)
707  fors_align_sky_exit("Cannot load dispersion solution");
708 
709  smapped = dfs_load_image(frameset, rectified_tag, CPL_TYPE_FLOAT, 0, 0);
710  if (smapped == NULL)
711  fors_align_sky_exit("Cannot load input rectified frame");
712 
713  wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
714 
715  if (wavelengths) {
716 
717  /*
718  * Cast the wavelengths into a (double precision) CPL vector
719  */
720 
721  nlines = cpl_table_get_nrow(wavelengths);
722 
723  if (nlines == 0)
724  fors_align_sky_exit("Empty input sky line catalog");
725 
726  if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
727  cpl_msg_error(recipe, "Missing column %s in input line "
728  "catalog table", wcolumn);
729  fors_align_sky_exit(NULL);
730  }
731 
732  line = cpl_malloc(nlines * sizeof(double));
733 
734  for (i = 0; i < nlines; i++)
735  line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
736 
737  cpl_table_delete(wavelengths); wavelengths = NULL;
738 
739  lines = cpl_vector_wrap(nlines, line);
740  }
741  else {
742  cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
743  }
744 
745  if (skyalign) {
746  cpl_msg_info(recipe, "Align wavelength solution to reference "
747  "skylines applying %d order residual fit...", skyalign);
748  }
749  else {
750  cpl_msg_info(recipe, "Align wavelength solution to reference "
751  "skylines applying median offset...");
752  }
753 
754  if (dispersion > 1.0)
755  highres = 0;
756  else
757  highres = 1;
758 
759  nx = cpl_image_get_size_x(coordinate);
760 
761  rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
762  endwavelength);
763 
764  offsets = mos_wavelength_align(smapped, slits, reference,
765  startwavelength, endwavelength,
766  idscoeff, lines, highres, skyalign,
767  rainbow, 4);
768 
769  cpl_vector_delete(lines); lines = NULL;
770  cpl_image_delete(smapped); smapped = NULL;
771 
772  if (offsets) {
773  if (dfs_save_table(frameset, offsets, shifts_tag, NULL,
774  parlist, recipe, version))
775  fors_align_sky_exit(NULL);
776 
777  cpl_table_delete(offsets); offsets = NULL;
778  }
779  else
780  fors_align_sky_exit("Alignment of the wavelength solution "
781  "to reference sky lines could not be done!");
782 
783  if (dfs_save_table(frameset, idscoeff, disp_ali_tag, NULL,
784  parlist, recipe, version))
785  fors_align_sky_exit(NULL);
786 
787  cpl_table_delete(idscoeff); idscoeff = NULL;
788 
789  wavemap = mos_map_wavelengths(coordinate, rainbow, slits,
790  polytraces, reference,
791  startwavelength, endwavelength,
792  dispersion);
793 
794  cpl_image_delete(rainbow); rainbow = NULL;
795  cpl_image_delete(coordinate); coordinate = NULL;
796  cpl_table_delete(polytraces); polytraces = NULL;
797  cpl_table_delete(slits); slits = NULL;
798 
799  if (dfs_save_image(frameset, wavemap, wavemap_tag,
800  header, parlist, recipe, version))
801  fors_align_sky_exit(NULL);
802 
803  cpl_image_delete(wavemap); wavemap = NULL;
804  cpl_propertylist_delete(header); header = NULL;
805 
806  return 0;
807 }
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: fors_bias.c:62
cpl_image * dfs_load_image(cpl_frameset *frameset, const char *category, cpl_type type, int ext, int calib)
Loading image data of given category.
Definition: fors_dfs.c:860
const char * dfs_get_parameter_string(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe string parameter value.
Definition: fors_dfs.c:602
cpl_propertylist * dfs_load_header(cpl_frameset *frameset, const char *category, int ext)
Loading header associated to data of given category.
Definition: fors_dfs.c:964
cpl_table * mos_load_slits_fors_mxu(cpl_propertylist *header)
Create slit location table from FITS header of FORS2-MXU data.
Definition: moses.c:14858
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.
Definition: moses.c:11380
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.
Definition: moses.c:15098
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.
Definition: moses.c:9986
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
Definition: fors_dfs.c:1683
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.
Definition: moses.c:11269
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.
Definition: fors_dfs.c:1451
cpl_table * dfs_load_table(cpl_frameset *frameset, const char *category, int ext)
Loading table data of given category.
Definition: fors_dfs.c:916
int dfs_get_parameter_int(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe integer parameter value.
Definition: fors_dfs.c:407
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.
Definition: fors_dfs.c:1575
Definition: list.c:74
double dfs_get_parameter_double(cpl_parameterlist *parlist, const char *name, const cpl_table *defaults)
Reading a recipe double parameter value.
Definition: fors_dfs.c:504