FORS Pipeline Reference Manual  5.0.9
fors_align_sky_lss.c
1 /* $Id: fors_align_sky_lss.c,v 1.9 2013-08-21 14:49:09 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-21 14:49:09 $
24  * $Revision: 1.9 $
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_lss_create(cpl_plugin *);
38 static int fors_align_sky_lss_exec(cpl_plugin *);
39 static int fors_align_sky_lss_destroy(cpl_plugin *);
40 static int fors_align_sky_lss(cpl_parameterlist *, cpl_frameset *);
41 
42 static char fors_align_sky_lss_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 scientific frames are produced by the recipes fors_remove_bias\n"
46 "and fors_flatfield. An input catalog of sky lines can be specified, or\n"
47 "an internal one is used.\n"
48 "\n"
49 "This recipe should be applied to LSS or long-slit like data (MOS/MXU with\n"
50 "all slits at the same offset). For multi-slit MOS/MXU data use recipe\n"
51 "fors_align_sky 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 "LSS, and SCI as STD.\n\n"
56 "Input files:\n\n"
57 " DO category: Type: Explanation: Required:\n"
58 " SCIENCE_UNBIAS_MXU\n"
59 " or SCIENCE_UNFLAT_MXU\n"
60 " or STANDARD_UNBIAS_MXU\n"
61 " or STANDARD_UNFLAT_MXU Calib Frame with sky lines Y\n"
62 " DISP_COEFF_MXU Calib Dispersion solution Y\n"
63 " SLIT_LOCATION_MXU Calib Slit location on CCD 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_LONG_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_lss_exit(message) \
73 { \
74 if ((const char *)message != NULL) cpl_msg_error(recipe, message); \
75 cpl_image_delete(wavemap); \
76 cpl_image_delete(rainbow); \
77 cpl_image_delete(smapped); \
78 cpl_table_delete(grism_table); \
79 cpl_table_delete(maskslits); \
80 cpl_table_delete(wavelengths); \
81 cpl_table_delete(offsets); \
82 cpl_table_delete(slits); \
83 cpl_table_delete(idscoeff); \
84 cpl_vector_delete(lines); \
85 cpl_propertylist_delete(header); \
86 cpl_msg_indent_less(); \
87 return -1; \
88 }
89 
90 #define fors_align_sky_lss_exit_memcheck(message) \
91 { \
92 if ((const char *)message != NULL) cpl_msg_info(recipe, message); \
93 printf("free wavemap (%p)\n", wavemap); \
94 cpl_image_delete(wavemap); \
95 printf("free rainbow (%p)\n", rainbow); \
96 cpl_image_delete(rainbow); \
97 printf("free smapped (%p)\n", smapped); \
98 cpl_image_delete(smapped); \
99 printf("free grism_table (%p)\n", grism_table); \
100 cpl_table_delete(grism_table); \
101 printf("free maskslits (%p)\n", maskslits); \
102 cpl_table_delete(maskslits); \
103 printf("free wavelengths (%p)\n", wavelengths); \
104 cpl_table_delete(wavelengths); \
105 printf("free offsets (%p)\n", offsets); \
106 cpl_table_delete(offsets); \
107 printf("free idscoeff (%p)\n", idscoeff); \
108 cpl_table_delete(idscoeff); \
109 printf("free slits (%p)\n", slits); \
110 cpl_table_delete(slits); \
111 printf("free lines (%p)\n", lines); \
112 cpl_vector_delete(lines); \
113 printf("free header (%p)\n", header); \
114 cpl_propertylist_delete(header); \
115 cpl_msg_indent_less(); \
116 return 0; \
117 }
118 
119 
131 int cpl_plugin_get_info(cpl_pluginlist *list)
132 {
133  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
134  cpl_plugin *plugin = &recipe->interface;
135 
136  cpl_plugin_init(plugin,
137  CPL_PLUGIN_API,
138  FORS_BINARY_VERSION,
139  CPL_PLUGIN_TYPE_RECIPE,
140  "fors_align_sky_lss",
141  "Upgrade wavelength solution using sky lines",
142  fors_align_sky_lss_description,
143  "Carlo Izzo",
144  PACKAGE_BUGREPORT,
145  "This file is currently part of the FORS Instrument Pipeline\n"
146  "Copyright (C) 2002-2010 European Southern Observatory\n\n"
147  "This program is free software; you can redistribute it and/or modify\n"
148  "it under the terms of the GNU General Public License as published by\n"
149  "the Free Software Foundation; either version 2 of the License, or\n"
150  "(at your option) any later version.\n\n"
151  "This program is distributed in the hope that it will be useful,\n"
152  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
153  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
154  "GNU General Public License for more details.\n\n"
155  "You should have received a copy of the GNU General Public License\n"
156  "along with this program; if not, write to the Free Software Foundation,\n"
157  "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n",
158  fors_align_sky_lss_create,
159  fors_align_sky_lss_exec,
160  fors_align_sky_lss_destroy);
161 
162  cpl_pluginlist_append(list, plugin);
163 
164  return 0;
165 }
166 
167 
178 static int fors_align_sky_lss_create(cpl_plugin *plugin)
179 {
180  cpl_recipe *recipe;
181  cpl_parameter *p;
182 
183  /*
184  * Check that the plugin is part of a valid recipe
185  */
186 
187  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
188  recipe = (cpl_recipe *)plugin;
189  else
190  return -1;
191 
192  /*
193  * Create the (empty) parameters list in the cpl_recipe object
194  */
195 
196  recipe->parameters = cpl_parameterlist_new();
197 
198  /*
199  * Dispersion
200  */
201 
202  p = cpl_parameter_new_value("fors.fors_align_sky_lss.dispersion",
203  CPL_TYPE_DOUBLE,
204  "Expected spectral dispersion (Angstrom/pixel)",
205  "fors.fors_align_sky_lss",
206  0.0);
207  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
208  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
209  cpl_parameterlist_append(recipe->parameters, p);
210 
211  /*
212  * Start wavelength for spectral extraction
213  */
214 
215  p = cpl_parameter_new_value("fors.fors_align_sky_lss.startwavelength",
216  CPL_TYPE_DOUBLE,
217  "Start wavelength in spectral extraction",
218  "fors.fors_align_sky_lss",
219  0.0);
220  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
221  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
222  cpl_parameterlist_append(recipe->parameters, p);
223 
224  /*
225  * End wavelength for spectral extraction
226  */
227 
228  p = cpl_parameter_new_value("fors.fors_align_sky_lss.endwavelength",
229  CPL_TYPE_DOUBLE,
230  "End wavelength in spectral extraction",
231  "fors.fors_align_sky_lss",
232  0.0);
233  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
234  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
235  cpl_parameterlist_append(recipe->parameters, p);
236 
237  /*
238  * Sky lines alignment
239  */
240 
241  p = cpl_parameter_new_value("fors.fors_align_sky_lss.skyalign",
242  CPL_TYPE_INT,
243  "Polynomial order for sky lines alignment",
244  "fors.fors_align_sky_lss",
245  0);
246  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "skyalign");
247  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
248  cpl_parameterlist_append(recipe->parameters, p);
249 
250  /*
251  * Line catalog table column containing the sky reference wavelengths
252  */
253 
254  p = cpl_parameter_new_value("fors.fors_align_sky_lss.wcolumn",
255  CPL_TYPE_STRING,
256  "Name of sky line catalog table column "
257  "with wavelengths",
258  "fors.fors_align_sky_lss",
259  "WLEN");
260  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wcolumn");
261  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
262  cpl_parameterlist_append(recipe->parameters, p);
263 
264  return 0;
265 }
266 
267 
276 static int fors_align_sky_lss_exec(cpl_plugin *plugin)
277 {
278  cpl_recipe *recipe;
279 
280  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
281  recipe = (cpl_recipe *)plugin;
282  else
283  return -1;
284 
285  return fors_align_sky_lss(recipe->parameters, recipe->frames);
286 }
287 
288 
297 static int fors_align_sky_lss_destroy(cpl_plugin *plugin)
298 {
299  cpl_recipe *recipe;
300 
301  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
302  recipe = (cpl_recipe *)plugin;
303  else
304  return -1;
305 
306  cpl_parameterlist_delete(recipe->parameters);
307 
308  return 0;
309 }
310 
311 
321 static int fors_align_sky_lss(cpl_parameterlist *parlist,
322  cpl_frameset *frameset)
323 {
324 
325  const char *recipe = "fors_align_sky_lss";
326 
327 
328  /*
329  * Input parameters
330  */
331 
332  double dispersion;
333  double startwavelength;
334  double endwavelength;
335  int skyalign;
336  const char *wcolumn;
337 
338  /*
339  * CPL objects
340  */
341 
342  cpl_image *rainbow = NULL;
343  cpl_image *wavemap = NULL;
344  cpl_image *smapped = NULL;
345  cpl_image *dummy = NULL;
346  cpl_table *grism_table = NULL;
347  cpl_table *wavelengths = NULL;
348  cpl_table *slits = NULL;
349  cpl_table *idscoeff = NULL;
350  cpl_table *maskslits = NULL;
351  cpl_table *offsets = NULL;
352  cpl_vector *lines = NULL;
353  cpl_propertylist *header = NULL;
354 
355  /*
356  * Auxiliary variables
357  */
358 
359  char version[80];
360  const char *slit_location_tag;
361  const char *rectified_tag;
362  const char *wavemap_tag;
363  const char *shifts_tag;
364  const char *disp_ali_tag;
365  const char *disp_coeff_tag;
366  int nframes;
367  int rebin;
368  int nlines;
369  int nx;
370  int ccd_xsize, ccd_ysize;
371  int first_row, last_row;
372  int ylow, yhig;
373  int highres;
374  int treat_as_lss;
375  int i;
376  double reference;
377  double *line;
378  int mxu, mos, lss;
379  int rec_scib;
380  int rec_stdb;
381  int rec_scif;
382  int rec_stdf;
383  int nslits_out_det = 0;
384 
385  char *instrume = NULL;
386 
387 
388  cpl_msg_set_indentation(2);
389 
390 
391  /*
392  * Get configuration parameters
393  */
394 
395  cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
396  cpl_msg_indent_more();
397 
398  if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
399  fors_align_sky_lss_exit("Too many in input: GRISM_TABLE");
400 
401  grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
402 
403  dispersion = dfs_get_parameter_double(parlist,
404  "fors.fors_align_sky_lss.dispersion", grism_table);
405 
406  if (dispersion <= 0.0)
407  fors_align_sky_lss_exit("Invalid spectral dispersion value");
408 
409  startwavelength = dfs_get_parameter_double(parlist,
410  "fors.fors_align_sky_lss.startwavelength", grism_table);
411  if (startwavelength > 1.0)
412  if (startwavelength < 3000.0 || startwavelength > 13000.0)
413  fors_align_sky_lss_exit("Invalid wavelength");
414 
415  endwavelength = dfs_get_parameter_double(parlist,
416  "fors.fors_align_sky_lss.endwavelength", grism_table);
417  if (endwavelength > 1.0) {
418  if (endwavelength < 3000.0 || endwavelength > 13000.0)
419  fors_align_sky_lss_exit("Invalid wavelength");
420  if (startwavelength < 1.0)
421  fors_align_sky_lss_exit("Invalid wavelength interval");
422  }
423 
424  if (startwavelength > 1.0)
425  if (endwavelength - startwavelength <= 0.0)
426  fors_align_sky_lss_exit("Invalid wavelength interval");
427 
428  skyalign = dfs_get_parameter_int(parlist,
429  "fors.fors_align_sky_lss.skyalign", NULL);
430 
431  if (skyalign < 0)
432  fors_align_sky_lss_exit("Invalid polynomial degree");
433  if (skyalign > 2)
434  fors_align_sky_lss_exit("Max polynomial degree for sky alignment is 2");
435 
436  wcolumn = dfs_get_parameter_string(parlist,
437  "fors.fors_align_sky_lss.wcolumn", NULL);
438 
439  cpl_table_delete(grism_table); grism_table = NULL;
440 
441  if (cpl_error_get_code())
442  fors_align_sky_lss_exit("Failure reading the configuration parameters");
443 
444 
445  cpl_msg_indent_less();
446  cpl_msg_info(recipe, "Check input set-of-frames:");
447  cpl_msg_indent_more();
448 
449  mxu = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_MXU");
450  mos = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_MOS");
451  lss = cpl_frameset_count_tags(frameset, "SLIT_LOCATION_LSS");
452 
453  nframes = mos + mxu + lss;
454 
455  if (nframes == 0) {
456  fors_align_sky_lss_exit("Missing input slit location table");
457  }
458  if (nframes > 1) {
459  cpl_msg_error(recipe,
460  "Too many input slit location tables (%d > 1)", nframes);
461  fors_align_sky_lss_exit(NULL);
462  }
463 
464  if (mxu) {
465  rec_scib = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_MXU");
466  rec_stdb = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_MXU");
467  rec_scif = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_MXU");
468  rec_stdf = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_MXU");
469  }
470  else if (mos) {
471  rec_scib = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_MOS");
472  rec_stdb = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_MOS");
473  rec_scif = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_MOS");
474  rec_stdf = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_MOS");
475  }
476  else {
477  rec_scib = cpl_frameset_count_tags(frameset, "SCIENCE_UNBIAS_LSS");
478  rec_stdb = cpl_frameset_count_tags(frameset, "STANDARD_UNBIAS_LSS");
479  rec_scif = cpl_frameset_count_tags(frameset, "SCIENCE_UNFLAT_LSS");
480  rec_stdf = cpl_frameset_count_tags(frameset, "STANDARD_UNFLAT_LSS");
481  }
482 
483  nframes = rec_scib + rec_stdb + rec_scif + rec_stdf;
484 
485  if (nframes == 0) {
486  fors_align_sky_lss_exit("Missing input scientific spectra");
487  }
488  if (nframes > 1) {
489  cpl_msg_error(recipe, "Too many input scientific spectra (%d > 1)",
490  nframes);
491  fors_align_sky_lss_exit(NULL);
492  }
493 
494  if (cpl_frameset_count_tags(frameset, "MASTER_SKYLINECAT") > 1)
495  fors_align_sky_lss_exit("Too many in input: MASTER_SKYLINECAT");
496 
497  if (rec_scib) {
498  if (mxu) {
499  rectified_tag = "SCIENCE_UNBIAS_MXU";
500  wavemap_tag = "WAVELENGTH_MAP_SCI_MXU";
501  shifts_tag = "SKY_SHIFTS_LONG_SCI_MXU";
502  disp_ali_tag = "DISP_COEFF_SCI_MXU";
503  }
504  else if (mos) {
505  rectified_tag = "SCIENCE_UNBIAS_MOS";
506  wavemap_tag = "WAVELENGTH_MAP_SCI_MOS";
507  shifts_tag = "SKY_SHIFTS_LONG_SCI_MOS";
508  disp_ali_tag = "DISP_COEFF_SCI_MOS";
509  }
510  else {
511  rectified_tag = "SCIENCE_UNBIAS_LSS";
512  wavemap_tag = "WAVELENGTH_MAP_SCI_LSS";
513  shifts_tag = "SKY_SHIFTS_LONG_SCI_LSS";
514  disp_ali_tag = "DISP_COEFF_SCI_LSS";
515  }
516  }
517  else if (rec_stdb) {
518  if (mxu) {
519  rectified_tag = "STANDARD_UNBIAS_MXU";
520  wavemap_tag = "WAVELENGTH_MAP_STD_MXU";
521  shifts_tag = "SKY_SHIFTS_LONG_STD_MXU";
522  disp_ali_tag = "DISP_COEFF_STD_MXU";
523  }
524  else if (mos) {
525  rectified_tag = "STANDARD_UNBIAS_MOS";
526  wavemap_tag = "WAVELENGTH_MAP_STD_MOS";
527  shifts_tag = "SKY_SHIFTS_LONG_STD_MOS";
528  disp_ali_tag = "DISP_COEFF_STD_MOS";
529  }
530  else {
531  rectified_tag = "STANDARD_UNBIAS_LSS";
532  wavemap_tag = "WAVELENGTH_MAP_STD_LSS";
533  shifts_tag = "SKY_SHIFTS_LONG_STD_LSS";
534  disp_ali_tag = "DISP_COEFF_STD_LSS";
535  }
536  }
537  else if (rec_scif) {
538  if (mxu) {
539  rectified_tag = "SCIENCE_UNFLAT_MXU";
540  wavemap_tag = "WAVELENGTH_MAP_SCI_MXU";
541  shifts_tag = "SKY_SHIFTS_LONG_SCI_MXU";
542  disp_ali_tag = "DISP_COEFF_SCI_MXU";
543  }
544  else if (mos) {
545  rectified_tag = "SCIENCE_UNFLAT_MOS";
546  wavemap_tag = "WAVELENGTH_MAP_SCI_MOS";
547  shifts_tag = "SKY_SHIFTS_LONG_SCI_MOS";
548  disp_ali_tag = "DISP_COEFF_SCI_MOS";
549  }
550  else {
551  rectified_tag = "SCIENCE_UNFLAT_LSS";
552  wavemap_tag = "WAVELENGTH_MAP_SCI_LSS";
553  shifts_tag = "SKY_SHIFTS_LONG_SCI_LSS";
554  disp_ali_tag = "DISP_COEFF_SCI_LSS";
555  }
556  }
557  else if (rec_stdf) {
558  if (mxu) {
559  rectified_tag = "STANDARD_UNFLAT_MXU";
560  wavemap_tag = "WAVELENGTH_MAP_STD_MXU";
561  shifts_tag = "SKY_SHIFTS_LONG_STD_MXU";
562  disp_ali_tag = "DISP_COEFF_STD_MXU";
563  }
564  else if (mos) {
565  rectified_tag = "STANDARD_UNFLAT_MOS";
566  wavemap_tag = "WAVELENGTH_MAP_STD_MOS";
567  shifts_tag = "SKY_SHIFTS_LONG_STD_MOS";
568  disp_ali_tag = "DISP_COEFF_STD_MOS";
569  }
570  else {
571  rectified_tag = "STANDARD_UNFLAT_LSS";
572  wavemap_tag = "WAVELENGTH_MAP_STD_LSS";
573  shifts_tag = "SKY_SHIFTS_LONG_STD_LSS";
574  disp_ali_tag = "DISP_COEFF_STD_LSS";
575  }
576  }
577 
578  nframes = cpl_frameset_count_tags(frameset, rectified_tag);
579 
580  if (nframes == 0) {
581  cpl_msg_error(recipe, "Missing input %s", rectified_tag);
582  fors_align_sky_lss_exit(NULL);
583  }
584  if (nframes > 1) {
585  cpl_msg_error(recipe, "Too many input %s (%d > 1)", rectified_tag,
586  nframes);
587  fors_align_sky_lss_exit(NULL);
588  }
589 
590 
591  if (mxu) {
592  disp_coeff_tag = "DISP_COEFF_MXU";
593  slit_location_tag = "SLIT_LOCATION_MXU";
594  }
595  else if (mos) {
596  disp_coeff_tag = "DISP_COEFF_MOS";
597  slit_location_tag = "SLIT_LOCATION_MOS";
598  }
599  else {
600  disp_coeff_tag = "DISP_COEFF_LSS";
601  slit_location_tag = "SLIT_LOCATION_LSS";
602  }
603 
604  nframes = cpl_frameset_count_tags(frameset, disp_coeff_tag);
605 
606  if (nframes == 0) {
607  cpl_msg_error(recipe, "Missing input %s", disp_coeff_tag);
608  fors_align_sky_lss_exit(NULL);
609  }
610  if (nframes > 1) {
611  cpl_msg_error(recipe, "Too many input %s (%d > 1)", disp_coeff_tag,
612  nframes);
613  fors_align_sky_lss_exit(NULL);
614  }
615 
616 
617  header = dfs_load_header(frameset, rectified_tag, 0);
618 
619  if (header == NULL)
620  fors_align_sky_lss_exit("Cannot load scientific frame header");
621 
622  if (mos || mxu) {
623  if (mos)
624  maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
625  else
626  maskslits = mos_load_slits_fors_mxu(header);
627 
628  /*
629  * Check if all slits have the same X offset: if not, abort!
630  */
631 
632  treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det);
633 
634  cpl_table_delete(maskslits); maskslits = NULL;
635 
636  if (!treat_as_lss)
637  fors_align_sky_lss_exit("This is not an LSS observation. "
638  "Please use recipe fors_align_sky");
639  }
640 
641  if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
642  cpl_msg_warning(cpl_func,"Input frames are not from the same grism");
643 
644  if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
645  cpl_msg_warning(cpl_func,"Input frames are not from the same filter");
646 
647  if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
648  cpl_msg_warning(cpl_func,"Input frames are not from the same chip");
649 
650 
651  /*
652  * Get the reference wavelength and the rebin factor along the
653  * dispersion direction from the reference frame
654  */
655 
656  instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
657  if (instrume == NULL)
658  fors_align_sky_lss_exit("Missing keyword INSTRUME in reference frame "
659  "header");
660 
661  if (instrume[4] == '1')
662  snprintf(version, 80, "%s/%s", "fors1", VERSION);
663  if (instrume[4] == '2')
664  snprintf(version, 80, "%s/%s", "fors2", VERSION);
665 
666  reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
667 
668  if (cpl_error_get_code() != CPL_ERROR_NONE)
669  fors_align_sky_lss_exit("Missing keyword ESO INS GRIS1 WLEN "
670  "in reference frame header");
671 
672  if (reference < 3000.0) /* Perhaps in nanometers... */
673  reference *= 10;
674 
675  if (reference < 3000.0 || reference > 13000.0) {
676  cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
677  "keyword ESO INS GRIS1 WLEN in reference frame header",
678  reference);
679  fors_align_sky_lss_exit(NULL);
680  }
681 
682  cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
683 
684  rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
685 
686  if (cpl_error_get_code() != CPL_ERROR_NONE)
687  fors_align_sky_lss_exit("Missing keyword ESO DET WIN1 BINX "
688  "in reference frame header");
689 
690  if (rebin != 1) {
691  dispersion *= rebin;
692  cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
693  "working dispersion used is %f A/pixel", rebin,
694  dispersion);
695  }
696 
697 
698  cpl_msg_indent_less();
699  cpl_msg_info(recipe, "Load input frames...");
700  cpl_msg_indent_more();
701 
702  smapped = dfs_load_image(frameset, rectified_tag, CPL_TYPE_FLOAT, 0, 0);
703  if (smapped == NULL)
704  fors_align_sky_lss_exit("Cannot load input scientific frame");
705 
706  slits = dfs_load_table(frameset, slit_location_tag, 1);
707  if (slits == NULL)
708  fors_align_sky_lss_exit("Cannot load slits location table");
709 
710  first_row = cpl_table_get_double(slits, "ybottom", 0, NULL);
711  last_row = cpl_table_get_double(slits, "ytop", 0, NULL);
712 
713  ylow = first_row + 1;
714  yhig = last_row + 1;
715 
716  ccd_xsize = cpl_image_get_size_x(smapped);
717  ccd_ysize = cpl_image_get_size_x(smapped);
718  dummy = cpl_image_extract(smapped, 1, ylow, ccd_xsize, yhig);
719  cpl_image_delete(smapped); smapped = dummy;
720  nx = ccd_xsize;
721 
722  cpl_table_delete(slits); slits = NULL;
723 
724  idscoeff = dfs_load_table(frameset, disp_coeff_tag, 1);
725  if (idscoeff == NULL)
726  fors_align_sky_lss_exit("Cannot load dispersion solution");
727 
728  wavelengths = dfs_load_table(frameset, "MASTER_SKYLINECAT", 1);
729 
730  if (wavelengths) {
731 
732  /*
733  * Cast the wavelengths into a (double precision) CPL vector
734  */
735 
736  nlines = cpl_table_get_nrow(wavelengths);
737 
738  if (nlines == 0)
739  fors_align_sky_lss_exit("Empty input sky line catalog");
740 
741  if (cpl_table_has_column(wavelengths, wcolumn) != 1) {
742  cpl_msg_error(recipe, "Missing column %s in input line "
743  "catalog table", wcolumn);
744  fors_align_sky_lss_exit(NULL);
745  }
746 
747  line = cpl_malloc(nlines * sizeof(double));
748 
749  for (i = 0; i < nlines; i++)
750  line[i] = cpl_table_get(wavelengths, wcolumn, i, NULL);
751 
752  cpl_table_delete(wavelengths); wavelengths = NULL;
753 
754  lines = cpl_vector_wrap(nlines, line);
755  }
756  else {
757  cpl_msg_info(recipe, "No sky line catalog found in input - fine!");
758  }
759 
760  if (skyalign) {
761  cpl_msg_info(recipe, "Align wavelength solution to reference "
762  "skylines applying %d order residual fit...", skyalign);
763  }
764  else {
765  cpl_msg_info(recipe, "Align wavelength solution to reference "
766  "skylines applying median offset...");
767  }
768 
769  if (dispersion > 1.0)
770  highres = 0;
771  else
772  highres = 1;
773 
774  rainbow = mos_map_idscoeff(idscoeff, nx, reference, startwavelength,
775  endwavelength);
776 
777  offsets = mos_wavelength_align_lss(smapped, reference,
778  startwavelength, endwavelength,
779  idscoeff, lines, highres,
780  skyalign, rainbow, 4);
781 
782  cpl_vector_delete(lines); lines = NULL;
783  cpl_image_delete(smapped); smapped = NULL;
784 
785  if (offsets) {
786  if (dfs_save_table(frameset, offsets, shifts_tag, NULL,
787  parlist, recipe, version))
788  fors_align_sky_lss_exit(NULL);
789 
790  cpl_table_delete(offsets); offsets = NULL;
791  }
792  else
793  fors_align_sky_lss_exit("Alignment of the wavelength solution "
794  "to reference sky lines could not be done!");
795 
796  if (dfs_save_table(frameset, idscoeff, disp_ali_tag, NULL,
797  parlist, recipe, version))
798  fors_align_sky_lss_exit(NULL);
799 
800  cpl_table_delete(idscoeff); idscoeff = NULL;
801 
802  wavemap = cpl_image_new(ccd_xsize, ccd_ysize, CPL_TYPE_FLOAT);
803  cpl_image_copy(wavemap, rainbow, 1, ylow);
804 
805  cpl_image_delete(rainbow); rainbow = NULL;
806 
807  if (dfs_save_image(frameset, wavemap, wavemap_tag,
808  header, parlist, recipe, version))
809  fors_align_sky_lss_exit(NULL);
810 
811  cpl_image_delete(wavemap); wavemap = NULL;
812  cpl_propertylist_delete(header); header = NULL;
813 
814  return 0;
815 }
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_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
int dfs_equal_keyword(cpl_frameset *frameset, const char *keyword)
Saving table data of given category.
Definition: fors_dfs.c:1683
cpl_table * mos_wavelength_align_lss(cpl_image *image, 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 (LSS).
Definition: moses.c:10539
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