IIINSTRUMENT Pipeline Reference Manual  6.2.2
isaac_spc_wlcalib.c
1 /* $Id: isaac_spc_wlcalib.c,v 1.26 2013-03-12 08:06:48 llundin Exp $
2  *
3  * This file is part of the ISAAC Pipeline
4  * Copyright (C) 2002,2003 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 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2013-03-12 08:06:48 $
24  * $Revision: 1.26 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 
39 #include "irplib_utils.h"
40 
41 #include "isaac_utils.h"
42 #include "isaac_wavelength.h"
43 #include "isaac_physicalmodel.h"
44 #include "isaac_pfits.h"
45 #include "isaac_dfs.h"
46 
47 /*-----------------------------------------------------------------------------
48  Functions prototypes
49  -----------------------------------------------------------------------------*/
50 
51 static int isaac_spc_wlcalib_create(cpl_plugin *);
52 static int isaac_spc_wlcalib_exec(cpl_plugin *);
53 static int isaac_spc_wlcalib_destroy(cpl_plugin *);
54 static int isaac_spc_wlcalib(cpl_parameterlist *, cpl_frameset *);
55 static cpl_table * isaac_spc_wlcalib_compute(const char *, const char *,
56  const char *, const char *);
57 static int isaac_spc_wlcalib_save(const cpl_table *, int, cpl_parameterlist *,
58  cpl_frameset *);
59 
60 /*-----------------------------------------------------------------------------
61  Static variables
62  -----------------------------------------------------------------------------*/
63 
64 static struct {
65  /* Inputs */
66  int rej_left;
67  int rej_right;
68  int rej_bottom;
69  int rej_top;
70  int max_offset;
71  int lines_table;
72  /* Outputs */
73  double disprel_cc;
74  int disprel_clines;
75  int disprel_dlines;
76  double disprel_rms;
77 } isaac_spc_wlcalib_config;
78 
79 static char isaac_spc_wlcalib_description[] =
80 "isaac_spc_wlcalib -- ISAAC wavelength calibration recipe\n"
81 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
82 "oh-cat.fits "ISAAC_CALPRO_OH_CAT" or\n"
83 "xe-cat.fits "ISAAC_CALPRO_XE_CAT" or\n"
84 "ar-cat.fits "ISAAC_CALPRO_AR_CAT"\n";
85 
86 /*-----------------------------------------------------------------------------
87  Functions code
88  -----------------------------------------------------------------------------*/
89 
90 /*----------------------------------------------------------------------------*/
98 /*----------------------------------------------------------------------------*/
99 int cpl_plugin_get_info(cpl_pluginlist * list)
100 {
101  cpl_recipe * recipe = cpl_calloc(1, sizeof(*recipe));
102  cpl_plugin * plugin = &recipe->interface;
103 
104  cpl_plugin_init(plugin,
105  CPL_PLUGIN_API,
106  ISAAC_BINARY_VERSION,
107  CPL_PLUGIN_TYPE_RECIPE,
108  "isaac_spc_wlcalib",
109  "Spectro wavelength calibration",
110  isaac_spc_wlcalib_description,
111  "Lars Lundin",
112  PACKAGE_BUGREPORT,
114  isaac_spc_wlcalib_create,
115  isaac_spc_wlcalib_exec,
116  isaac_spc_wlcalib_destroy);
117 
118  cpl_pluginlist_append(list, plugin);
119 
120  return 0;
121 }
122 
123 /*----------------------------------------------------------------------------*/
132 /*----------------------------------------------------------------------------*/
133 static int isaac_spc_wlcalib_create(cpl_plugin * plugin)
134 {
135  cpl_recipe * recipe;
136  cpl_parameter * p;
137 
138  /* Get the recipe out of the plugin */
139  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
140  recipe = (cpl_recipe *)plugin;
141  else return CPL_ERROR_UNSPECIFIED;
142 
143  /* Create the parameters list in the cpl_recipe object */
144  recipe->parameters = cpl_parameterlist_new();
145 
146  /* Fill the parameters list */
147  /* --rejected */
148  p = cpl_parameter_new_value("isaac.isaac_spc_wlcalib.rejected",
149  CPL_TYPE_STRING, "left right bottom top rejections",
150  "isaac.isaac_spc_wlcalib", "-1 -1 100 100");
151  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rej");
152  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
153  cpl_parameterlist_append(recipe->parameters, p);
154  /* --max_offset */
155  p = cpl_parameter_new_value("isaac.isaac_spc_wlcalib.max_offset",
156  CPL_TYPE_INT, "maximum offset from the physical model "
157  "allowed in pixels", "isaac.isaac_spc_wlcalib", 50);
158  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "max_offset");
159  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
160  cpl_parameterlist_append(recipe->parameters, p);
161  /* --lines */
162  p = cpl_parameter_new_value("isaac.isaac_spc_wlcalib.lines", CPL_TYPE_INT,
163  "1 for oh, 2 for xe, 3 for ar, 4 for xe+ar",
164  "isaac.isaac_spc_wlcalib", -1);
165  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "lines");
166  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
167  cpl_parameterlist_append(recipe->parameters, p);
168  return 0;
169 }
170 
171 /*----------------------------------------------------------------------------*/
177 /*----------------------------------------------------------------------------*/
178 static int isaac_spc_wlcalib_exec(cpl_plugin * plugin)
179 {
180  cpl_recipe * recipe;
181 
182  /* Get the recipe out of the plugin */
183  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
184  recipe = (cpl_recipe *)plugin;
185  else return CPL_ERROR_UNSPECIFIED;
186 
187  return isaac_spc_wlcalib(recipe->parameters, recipe->frames);
188 }
189 
190 /*----------------------------------------------------------------------------*/
196 /*----------------------------------------------------------------------------*/
197 static int isaac_spc_wlcalib_destroy(cpl_plugin * plugin)
198 {
199  cpl_recipe * recipe;
200 
201  /* Get the recipe out of the plugin */
202  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
203  recipe = (cpl_recipe *)plugin;
204  else return CPL_ERROR_UNSPECIFIED;
205 
206  cpl_parameterlist_delete(recipe->parameters);
207  return 0;
208 }
209 
210 /*----------------------------------------------------------------------------*/
217 /*----------------------------------------------------------------------------*/
218 static int isaac_spc_wlcalib(
219  cpl_parameterlist * parlist,
220  cpl_frameset * framelist)
221 {
222  cpl_parameter * par;
223  cpl_frame * cur_frame;
224  const char * cur_fname;
225  const char * sval;
226  const char * oh;
227  const char * xe;
228  const char * ar;
229  cpl_table * tab;
230 
231  /* Initialise */
232  par = NULL;
233 
234  /* Retrieve input parameters */
235  /* Rejection parameters */
236  par = cpl_parameterlist_find(parlist, "isaac.isaac_spc_wlcalib.rejected");
237  sval = cpl_parameter_get_string(par);
238  if (sscanf(sval, "%d %d %d %d",
239  &isaac_spc_wlcalib_config.rej_left,
240  &isaac_spc_wlcalib_config.rej_right,
241  &isaac_spc_wlcalib_config.rej_bottom,
242  &isaac_spc_wlcalib_config.rej_top) != 4) {
243  return CPL_ERROR_UNSPECIFIED;
244  }
245 
246  /* Max offset in pixels */
247  par = cpl_parameterlist_find(parlist, "isaac.isaac_spc_wlcalib.max_offset");
248  isaac_spc_wlcalib_config.max_offset = cpl_parameter_get_int(par);
249 
250  /* --lines */
251  par = cpl_parameterlist_find(parlist, "isaac.isaac_spc_wlcalib.lines");
252  isaac_spc_wlcalib_config.lines_table=cpl_parameter_get_int(par);
253 
254  /* Check lines */
255  if (isaac_spc_wlcalib_config.lines_table < 1) {
256  cpl_msg_error(cpl_func, "Please specify the catalog");
257  return CPL_ERROR_UNSPECIFIED;
258  }
259 
260  /* Retrieve calibration data */
261  oh = isaac_extract_filename(framelist, ISAAC_CALPRO_OH_CAT);
262  xe = isaac_extract_filename(framelist, ISAAC_CALPRO_XE_CAT);
263  ar = isaac_extract_filename(framelist, ISAAC_CALPRO_AR_CAT);
264 
265  /* Reduce the images */
266  cur_frame = cpl_frameset_get_position(framelist, 0);
267  cur_fname = cpl_frame_get_filename(cur_frame);
268  cpl_msg_info(cpl_func, "Reduce %s", cur_fname);
269  cpl_msg_indent_more();
270 
271  /* Apply the wl calib */
272  if ((tab = isaac_spc_wlcalib_compute(cur_fname, oh, ar, xe)) == NULL) {
273  cpl_msg_warning(cpl_func, "cannot reduce");
274  } else {
275  /* Save the file */
276  if (isaac_spc_wlcalib_save(tab, 1, parlist, framelist) != 0) {
277  cpl_msg_warning(cpl_func, "cannot save");
278  }
279  cpl_table_delete(tab);
280  }
281  cpl_msg_indent_less();
282 
283  /* Free and return */
284  return 0;
285 }
286 
287 /*----------------------------------------------------------------------------*/
297 /*----------------------------------------------------------------------------*/
298 static cpl_table * isaac_spc_wlcalib_compute(
299  const char * in_name,
300  const char * oh,
301  const char * ar,
302  const char * xe)
303 {
304  double slit_width;
305  int order;
306  double * phdisprel;
307  cpl_image * in;
308  computed_disprel * disprel;
309  cpl_table * out_tab;
310  const char * lines_tab;
311 
312  /* Compute the slit_width */
313  if ((slit_width = isaac_get_slitwidth(in_name)) == -1) {
314  cpl_msg_error(cpl_func, "cannot get the slit width");
315  return NULL;
316  }
317 
318  /* Get the order */
319  if ((order = isaac_find_order(in_name)) == -1) {
320  cpl_msg_error(cpl_func, "cannot get the order");
321  return NULL;
322  }
323 
324  /* First estimation using a physical model */
325  cpl_msg_info(cpl_func, "Compute the physical model");
326  cpl_msg_indent_more();
327  if ((phdisprel = isaac_get_disprel_estimate(in_name, 3)) == NULL) {
328  cpl_msg_error(cpl_func, "cannot estimate the dispersion relation");
329  cpl_msg_indent_less();
330  return NULL;
331  }
332  cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
333  phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
334  cpl_msg_indent_less();
335 
336  /* Load the image */
337  if ((in = cpl_image_load(in_name, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
338  cpl_msg_error(cpl_func, "cannot load the image");
339  cpl_free(phdisprel);
340  return NULL;
341  }
342 
343  /* Compute the dispersion relation */
344  switch (isaac_spc_wlcalib_config.lines_table) {
345  case 1: lines_tab = "oh"; break;
346  case 2: lines_tab = "Xe"; break;
347  case 3: lines_tab = "Ar"; break;
348  case 4: lines_tab = "Xe+Ar"; break;
349  default:
350  cpl_image_delete(in);
351  return NULL;
352  }
353  cpl_msg_info(cpl_func, "Compute the dispersion relation");
354  cpl_msg_indent_more();
355  if ((disprel = spectro_compute_disprel(in,
356  isaac_spc_wlcalib_config.rej_bottom,
357  isaac_spc_wlcalib_config.rej_top,
358  isaac_spc_wlcalib_config.rej_left,
359  isaac_spc_wlcalib_config.rej_right,
360  isaac_spc_wlcalib_config.max_offset,
361  isaac_has_thermal(in_name) > 0,
362  lines_tab, oh, ar, xe, slit_width, order,
363  (int)(cpl_msg_get_level() == CPL_MSG_DEBUG),
364  phdisprel)) == NULL) {
365  cpl_msg_error(cpl_func, "cannot compute the dispersion relation");
366  cpl_image_delete(in);
367  cpl_free(phdisprel);
368  cpl_msg_indent_less();
369  return NULL;
370  }
371  cpl_image_delete(in);
372  cpl_free(phdisprel);
373 
374  cpl_msg_info(cpl_func, "Cross correlation factor: %g", disprel->cc);
375  cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
376  disprel->poly[0], disprel->poly[1], disprel->poly[2],
377  disprel->poly[3]);
378  cpl_msg_indent_less();
379 
380  /* Create the output table and store the relevant information */
381  out_tab = cpl_table_new(4);
382 
383  /* Fill dispersion relation */
384  cpl_table_new_column(out_tab, "WL_coefficients", CPL_TYPE_DOUBLE);
385  cpl_table_set_double(out_tab, "WL_coefficients", 0, disprel->poly[0]);
386  cpl_table_set_double(out_tab, "WL_coefficients", 1, disprel->poly[1]);
387  cpl_table_set_double(out_tab, "WL_coefficients", 2, disprel->poly[2]);
388  cpl_table_set_double(out_tab, "WL_coefficients", 3, disprel->poly[3]);
389  isaac_spc_wlcalib_config.disprel_cc = disprel->cc;
390  isaac_spc_wlcalib_config.disprel_clines = disprel->clines;
391  isaac_spc_wlcalib_config.disprel_dlines = disprel->dlines;
392  isaac_spc_wlcalib_config.disprel_rms = disprel->rms;
393 
394  /* Free and return */
395  if (disprel->poly != NULL) cpl_free(disprel->poly);
396  cpl_free(disprel);
397  return out_tab;
398 }
399 
400 /*----------------------------------------------------------------------------*/
409 /*----------------------------------------------------------------------------*/
410 static int isaac_spc_wlcalib_save(
411  const cpl_table * tab,
412  int nb,
413  cpl_parameterlist * parlist,
414  cpl_frameset * set)
415 {
416  cpl_propertylist * plist;
417  cpl_propertylist * qclist;
418  cpl_propertylist * paflist;
419  const cpl_frame * ref_frame;
420  const char * sval;
421  char * filename;
422 
423  /* Get the QC params in qclist */
424  qclist = cpl_propertylist_new();
425 
426  /* Get the reference frame */
427  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
428  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
429  0)) == NULL) {
430  cpl_msg_error(cpl_func, "getting header from reference frame");
431  cpl_propertylist_delete(qclist);
432  return CPL_ERROR_UNSPECIFIED;
433  }
434  /* Test the status */
435  if (cpl_error_get_code()) {
436  cpl_propertylist_delete(qclist);
437  cpl_propertylist_delete(plist);
438  return CPL_ERROR_UNSPECIFIED;
439  }
440  sval = isaac_pfits_get_filter(plist);
441  if (cpl_error_get_code()) cpl_error_reset();
442  else cpl_propertylist_append_string(plist, "ESO QC FILTER OBS", sval);
443  cpl_propertylist_delete(plist);
444  cpl_propertylist_append_int(plist, "ESO QC LAMP",
445  isaac_spc_wlcalib_config.lines_table);
446  cpl_propertylist_append_double(plist, "ESO QC DISP XCORR",
447  isaac_spc_wlcalib_config.disprel_cc);
448  cpl_propertylist_append_int(plist, "ESO QC DISP NUMCAT",
449  isaac_spc_wlcalib_config.disprel_clines);
450  cpl_propertylist_append_int(plist, "ESO QC DISP NUMMATCH",
451  isaac_spc_wlcalib_config.disprel_dlines);
452  cpl_propertylist_append_double(plist, "ESO QC DISP STDEV",
453  isaac_spc_wlcalib_config.disprel_rms);
454  cpl_propertylist_append_double(plist, "ESO QC DISPCO1",
455  cpl_table_get_double(tab, "WL_coefficients", 0, NULL));
456  cpl_propertylist_append_double(plist, "ESO QC DISPCO2",
457  cpl_table_get_double(tab, "WL_coefficients", 1, NULL));
458  cpl_propertylist_append_double(plist, "ESO QC DISPCO3",
459  cpl_table_get_double(tab, "WL_coefficients", 2, NULL));
460  cpl_propertylist_append_double(plist, "ESO QC DISPCO4",
461  cpl_table_get_double(tab, "WL_coefficients", 3, NULL));
462  cpl_propertylist_append_double(plist, "ESO QC WLEN",
463  (double)(cpl_table_get_double(tab, "WL_coefficients", 0, NULL) +
464  512*cpl_table_get_double(tab, "WL_coefficients", 1, NULL) +
465  512*512*cpl_table_get_double(tab, "WL_coefficients", 2, NULL) +
466  512*512*512*cpl_table_get_double(tab, "WL_coefficients", 3, NULL)));
467 
468  /* Write the table */
469  filename = cpl_sprintf("isaac_spc_wlcalib_%d.fits", nb);
470  irplib_dfs_save_table(set,
471  parlist,
472  set,
473  tab,
474  NULL,
475  "isaac_spc_wlcalib",
476  ISAAC_SPC_WLCALIB_RES,
477  qclist,
478  NULL,
479  PACKAGE "/" PACKAGE_VERSION,
480  filename);
481  cpl_free(filename);
482 
483  /* Get the reference frame */
484  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
485 
486  /* Get FITS header from reference file */
487  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
488  0)) == NULL) {
489  cpl_msg_error(cpl_func, "getting header from reference frame");
490  cpl_propertylist_delete(qclist);
491  return CPL_ERROR_UNSPECIFIED;
492  }
493 
494  /* Get the keywords for the paf file */
495  paflist = cpl_propertylist_new();
496  cpl_propertylist_copy_property_regexp(paflist, plist,
497  "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
498  "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
499  "ESO INS GRAT WLEN|ESO INS GRAT ORDER|ESO INS MODE|"
500  "ESO INS OPTI1 ID)$", 0);
501  cpl_propertylist_delete(plist);
502 
503  /* Copy the QC in paflist */
504  cpl_propertylist_copy_property_regexp(paflist, qclist, ".", 0);
505  cpl_propertylist_delete(qclist);
506 
507  /* PRO.CATG */
508  cpl_propertylist_update_string(paflist, CPL_DFS_PRO_CATG,
509  ISAAC_SPC_WLCALIB_RES);
510 
511  /* Save the PAF file */
512  filename = cpl_sprintf("isaac_spc_wlcalib_%d.paf", nb);
513  cpl_dfs_save_paf("ISAAC",
514  "isaac_spc_wlcalib",
515  paflist,
516  filename);
517  cpl_free(filename);
518  cpl_propertylist_delete(paflist);
519  return 0;
520 }
521 
const char * isaac_pfits_get_filter(const cpl_propertylist *plist)
find out the filter
Definition: isaac_pfits.c:880
double * isaac_get_disprel_estimate(const char *filename, cpl_size poly_deg)
Estimate the instrument wavelength range.
const char * isaac_extract_filename(const cpl_frameset *self, const char *tag)
Extract the filename of the first frame of the given tag.
Definition: isaac_utils.c:397
const char * isaac_get_license(void)
Get the pipeline copyright and license.
Definition: isaac_utils.c:62