IIINSTRUMENT Pipeline Reference Manual 6.2.5
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
51static int isaac_spc_wlcalib_create(cpl_plugin *);
52static int isaac_spc_wlcalib_exec(cpl_plugin *);
53static int isaac_spc_wlcalib_destroy(cpl_plugin *);
54static int isaac_spc_wlcalib(cpl_parameterlist *, cpl_frameset *);
55static cpl_table * isaac_spc_wlcalib_compute(const char *, const char *,
56 const char *, const char *);
57static int isaac_spc_wlcalib_save(const cpl_table *, int, cpl_parameterlist *,
58 cpl_frameset *);
59
60/*-----------------------------------------------------------------------------
61 Static variables
62 -----------------------------------------------------------------------------*/
63
64static 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
79static 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/*----------------------------------------------------------------------------*/
99int 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/*----------------------------------------------------------------------------*/
133static 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/*----------------------------------------------------------------------------*/
178static 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/*----------------------------------------------------------------------------*/
197static 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/*----------------------------------------------------------------------------*/
218static 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/*----------------------------------------------------------------------------*/
298static 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/*----------------------------------------------------------------------------*/
410static 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