CRIRES Pipeline Reference Manual 2.3.18
crires_util_wlcalib.c
1/* $Id: crires_util_wlcalib.c,v 1.69 2012-09-20 12:06:34 yjung Exp $
2 *
3 * This file is part of the crires 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: yjung $
23 * $Date: 2012-09-20 12:06:34 $
24 * $Revision: 1.69 $
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 <locale.h>
37#include "crires_recipe.h"
38
39#include "irplib_wlxcorr.h"
40#include "irplib_utils.h"
41
42#include "crires_wlcalib.h"
43#include "crires_wlestimate.h"
44
45/*-----------------------------------------------------------------------------
46 Define
47 -----------------------------------------------------------------------------*/
48
49#define RECIPE_STRING "crires_util_wlcalib"
50
51/*-----------------------------------------------------------------------------
52 Functions prototypes
53 -----------------------------------------------------------------------------*/
54
55static int crires_util_wlcalib_save(const cpl_imagelist *, const cpl_table **,
56 const cpl_table **, const cpl_parameterlist *, cpl_frameset *) ;
57
58static char crires_util_wlcalib_description[] =
59"This recipe accepts 2 parameters:\n"
60"First parameter: the extracted spectrum in pixels.\n"
61" (PRO TYPE = "CRIRES_PROTYPE_SPEC_PIX")\n"
62"Second parameter: the table with the lines catalog.\n"
63" (PRO TYPE = "CRIRES_PROTYPE_CATALOG")\n"
64"\n"
65"This recipe produces 2 files:\n"
66"First product: the image with the wavelength values.\n"
67" (PRO TYPE = "CRIRES_PROTYPE_WL_MAP")\n"
68"Second product: the table with the wavelength polynomial coefficients.\n"
69" (PRO TYPE = "CRIRES_PROTYPE_WL_POLY")\n" ;
70
71CRIRES_RECIPE_DEFINE(crires_util_wlcalib,
72 CRIRES_PARAM_WAVES |
73 CRIRES_PARAM_DISPLAY |
74 CRIRES_PARAM_WL_LOG |
75 CRIRES_PARAM_WL_NOLIMIT |
76 CRIRES_PARAM_WL_ERROR |
77 CRIRES_PARAM_XC_LIMIT |
78 CRIRES_PARAM_WL_NBSAMPLES |
79 CRIRES_PARAM_DEGREE |
80 CRIRES_PARAM_WL_CLEAN |
81 CRIRES_PARAM_LINES |
82 CRIRES_PARAM_FIRST_PLOTTED |
83 CRIRES_PARAM_LAST_PLOTTED,
84 "Wavelength calibration of a spectrum",
85 crires_util_wlcalib_description) ;
86
87/*-----------------------------------------------------------------------------
88 Static variables
89 -----------------------------------------------------------------------------*/
90
91static struct {
92 /* Inputs */
93 double wstart[CRIRES_NB_DETECTORS] ;
94 double wstop[CRIRES_NB_DETECTORS] ;
95 int display ;
96 int degree ;
97 int wl_nolimit ;
98 int wl_log ;
99 double wl_err ;
100 int wl_nsamples ;
101 int wl_clean ;
102 double wl_xclimit ;
103 int use_ppm ;
104 int slitw ;
105 int fwhm ;
106 const char * lines ;
107 int first_plotted_line ;
108 int last_plotted_line ;
109 /* Output */
110 int win_mode ;
111 crires_illum_period period ;
112 double qc_wlcent[CRIRES_NB_DETECTORS] ;
113 double qc_wldisp[CRIRES_NB_DETECTORS] ;
114 double qc_wlxc[CRIRES_NB_DETECTORS] ;
115} crires_util_wlcalib_config ;
116
117/*-----------------------------------------------------------------------------
118 Functions code
119 -----------------------------------------------------------------------------*/
120
121/*----------------------------------------------------------------------------*/
128/*----------------------------------------------------------------------------*/
129static int crires_util_wlcalib(
130 cpl_frameset * frameset,
131 const cpl_parameterlist * parlist)
132{
133 cpl_table * ext_spec ;
134 const char * fname ;
135 cpl_propertylist * plist ;
136 double wmin, wmax ;
137 cpl_vector * spec ;
138 double * pspec ;
139 cpl_polynomial * phdisp ;
140 cpl_polynomial * poly_sol ;
141 cpl_matrix * samppos ;
142 cpl_size mindeg, maxdeg ;
143 cpl_bivector * lines_biv ;
144 cpl_table * cat ;
145 double val ;
146 cpl_table * real_sol ;
147 int nrows, spec_pos ;
148 cpl_bivector * cat_biv ;
149 double * cat_biv_x ;
150 double * cat_biv_y ;
151 const char * sval ;
152 cpl_frame * fr ;
153 cpl_polynomial * disp_poly ;
154 cpl_table * wl_infos[CRIRES_NB_DETECTORS] ;
155 cpl_table * wl_tab[CRIRES_NB_DETECTORS] ;
156 cpl_imagelist * wl_map ;
157 int i, j ;
158
159 /* Needed for sscanf() */
160 setlocale(LC_NUMERIC, "C");
161
162 /* Initialise */
163 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
164 crires_util_wlcalib_config.qc_wlcent[i] = -1.0 ;
165 crires_util_wlcalib_config.qc_wldisp[i] = -1.0 ;
166 crires_util_wlcalib_config.qc_wlxc[i] = -1.0 ;
167 wl_tab[i] = NULL ;
168 wl_infos[i] = NULL ;
169 }
170 crires_util_wlcalib_config.lines = NULL ;
171 crires_util_wlcalib_config.use_ppm = 0 ;
172 crires_util_wlcalib_config.slitw = 2 ;
173 crires_util_wlcalib_config.fwhm = 2 ;
174
175 /* Retrieve input parameters */
176 sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
177 CRIRES_PARAM_WAVES) ;
178 if (sscanf(sval, "%lg,%lg,%lg,%lg,%lg,%lg,%lg,%lg",
179 &crires_util_wlcalib_config.wstart[0],
180 &crires_util_wlcalib_config.wstop[0],
181 &crires_util_wlcalib_config.wstart[1],
182 &crires_util_wlcalib_config.wstop[1],
183 &crires_util_wlcalib_config.wstart[2],
184 &crires_util_wlcalib_config.wstop[2],
185 &crires_util_wlcalib_config.wstart[3],
186 &crires_util_wlcalib_config.wstop[3])!=2*CRIRES_NB_DETECTORS){
187 return -1 ;
188 }
189 crires_util_wlcalib_config.display = crires_parameterlist_get_int(parlist,
190 RECIPE_STRING, CRIRES_PARAM_DISPLAY) ;
191 crires_util_wlcalib_config.degree = crires_parameterlist_get_int(parlist,
192 RECIPE_STRING, CRIRES_PARAM_DEGREE) ;
193 crires_util_wlcalib_config.wl_log = crires_parameterlist_get_bool(parlist,
194 RECIPE_STRING, CRIRES_PARAM_WL_LOG) ;
195 crires_util_wlcalib_config.wl_nolimit = crires_parameterlist_get_bool(
196 parlist, RECIPE_STRING, CRIRES_PARAM_WL_NOLIMIT) ;
197 crires_util_wlcalib_config.wl_err = crires_parameterlist_get_double(parlist,
198 RECIPE_STRING, CRIRES_PARAM_WL_ERROR) ;
199 crires_util_wlcalib_config.wl_xclimit = crires_parameterlist_get_double(
200 parlist, RECIPE_STRING, CRIRES_PARAM_XC_LIMIT) ;
201 crires_util_wlcalib_config.wl_nsamples = crires_parameterlist_get_int(
202 parlist, RECIPE_STRING, CRIRES_PARAM_WL_NBSAMPLES) ;
203 crires_util_wlcalib_config.wl_clean = crires_parameterlist_get_bool(parlist,
204 RECIPE_STRING, CRIRES_PARAM_WL_CLEAN) ;
205 crires_util_wlcalib_config.lines = crires_parameterlist_get_string(parlist,
206 RECIPE_STRING, CRIRES_PARAM_LINES) ;
207 crires_util_wlcalib_config.first_plotted_line=crires_parameterlist_get_int(
208 parlist, RECIPE_STRING, CRIRES_PARAM_FIRST_PLOTTED) ;
209 crires_util_wlcalib_config.last_plotted_line=crires_parameterlist_get_int(
210 parlist, RECIPE_STRING, CRIRES_PARAM_LAST_PLOTTED) ;
211
212 /* Identify the RAW and CALIB frames in the input frameset */
213 if (crires_dfs_set_groups(frameset, NULL)) {
214 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
215 return -1 ;
216 }
217
218 /* Check that we have 2 files in input */
219 if (cpl_frameset_get_size(frameset) != 2) {
220 cpl_msg_error(__func__, "Expects 2 files in input") ;
221 return -1 ;
222 }
223
224 /* Get the detector illumination period */
225 fr = cpl_frameset_get_position(frameset, 0);
226 crires_util_wlcalib_config.period =
227 crires_get_detector_illum_period(cpl_frame_get_filename(fr)) ;
228 if (crires_util_wlcalib_config.period == CRIRES_ILLUM_UNKNOWN) {
229 cpl_msg_error(__func__,
230 "Cannot determine the detector illumination period") ;
231 return -1 ;
232 }
233
234 /* Windowing mode ? */
235 if ((plist=cpl_propertylist_load(cpl_frame_get_filename(fr), 0)) == NULL)
236 return -1 ;
237 sval = crires_pfits_get_ncorrs(plist) ;
238 if (!strcmp(sval, "FowlerNsampGRstWin")) {
239 crires_util_wlcalib_config.period = CRIRES_ILLUM_FULL_DETECTOR ;
240 crires_util_wlcalib_config.win_mode = 1 ;
241 } else {
242 crires_util_wlcalib_config.win_mode = 0 ;
243 }
244 cpl_propertylist_delete(plist) ;
245
246 /* Display the Detector illumination */
247 crires_display_detector_illum(crires_util_wlcalib_config.period) ;
248
249 /* Load the second file */
250 cpl_msg_info(__func__, "Second frame validity check") ;
251 cpl_msg_indent_more() ;
252 fr = cpl_frameset_get_position(frameset, 1);
253 cat = crires_load_table_check(cpl_frame_get_filename(fr), 1,
254 CRIRES_PROTYPE_CATALOG, -1, -1, 0) ;
255 if (cat == NULL) {
256 cpl_msg_error(__func__, "Second frame is incorrect") ;
257 cpl_msg_indent_less() ;
258 return -1 ;
259 }
260 cpl_msg_indent_less() ;
261
262 /* Create the catalog spectrum in a bivector */
263 nrows = cpl_table_get_nrow(cat) ;
264 cat_biv = cpl_bivector_new(nrows) ;
265 cat_biv_x = cpl_bivector_get_x_data(cat_biv) ;
266 cat_biv_y = cpl_bivector_get_y_data(cat_biv) ;
267 for (i=0 ; i<nrows ; i++) {
268 cat_biv_x[i] = cpl_table_get(cat, CRIRES_COL_WAVELENGTH, i, NULL) ;
269 val = cpl_table_get(cat, CRIRES_COL_EMISSION, i, NULL) ;
270 if (crires_util_wlcalib_config.wl_log && val > 0)
271 cat_biv_y[i] = log10(val) ;
272 else
273 cat_biv_y[i] = val ;
274 }
275 cpl_table_delete(cat) ;
276
277 /* Get the raw file name */
278 fr = cpl_frameset_get_position(frameset, 0);
279 fname = cpl_frame_get_filename(fr) ;
280
281 /* Get the Minimum and Maximum wavelengths */
282 if (crires_util_wlcalib_config.wl_nolimit == 0) {
283 plist = cpl_propertylist_load(fname, 0) ;
284 wmin = crires_pfits_get_wlen_min(plist) ;
285 wmax = crires_pfits_get_wlen_max(plist) ;
286 cpl_propertylist_delete(plist) ;
287 if (cpl_error_get_code()) {
288 wmin = wmax = -1.0 ;
289 cpl_error_reset() ;
290 }
291 } else {
292 wmin = wmax = -1.0 ;
293 }
294
295 /* Loop on the spectra to calibrate */
296 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
297 /* Skip some detectors in windowing mode */
298 if ((i==0 || i==CRIRES_NB_DETECTORS-1) &&
299 (crires_util_wlcalib_config.win_mode == 1)) {
300 continue ;
301 }
302
303 cpl_msg_info(__func__, "Wavelength calibration for chip %d", i+1) ;
304 /* Load the first file in table */
305 cpl_msg_info(__func__, "Load the extracted table") ;
306 cpl_msg_indent_more() ;
307 if ((ext_spec=crires_load_table_check(fname, i+1,
308 CRIRES_PROTYPE_SPEC_PIX, -1, -1, 0)) == NULL) {
309 cpl_msg_warning(__func__, "Empty extension") ;
310 cpl_msg_indent_less() ;
311 continue ;
312 }
313 cpl_msg_indent_less() ;
314
315 /* Get the Wavlength estimation */
316 cpl_msg_info(__func__, "Wavelength estimation") ;
317 cpl_msg_indent_more() ;
318 if ((phdisp = crires_wlestimate_compute(
319 crires_util_wlcalib_config.wstart[i],
320 crires_util_wlcalib_config.wstop[i])) == NULL) {
321 if ((phdisp = crires_wlestimate_get(fname, i+1)) == NULL) {
322 cpl_msg_error(__func__, "Cannot get the wavelength estimate") ;
323 cpl_msg_indent_less() ;
324 cpl_table_delete(ext_spec) ;
325 continue ;
326 }
327 }
328 cpl_msg_indent_less() ;
329
330 /* Convert to vector */
331 nrows = cpl_table_get_nrow(ext_spec) ;
332 spec = cpl_vector_new(nrows) ;
333 pspec = cpl_vector_get_data(spec) ;
334 for (j=0 ; j<nrows ; j++) {
335 pspec[j] = cpl_table_get(ext_spec, CRIRES_COL_EXTRACT_INT_RECT, j,
336 NULL);
337 }
338 cpl_table_delete(ext_spec) ;
339
340 /* Wavelength calibration */
341 cpl_msg_info(__func__, "Wavelength calibration computation") ;
342 cpl_msg_indent_more() ;
343 if ((disp_poly = crires_wlcalib_engine(spec, cat_biv, phdisp,
344 crires_util_wlcalib_config.slitw,
345 crires_util_wlcalib_config.fwhm,
346 crires_util_wlcalib_config.degree,
347 wmin, wmax,
348 crires_util_wlcalib_config.wl_err,
349 crires_util_wlcalib_config.wl_nsamples,
350 crires_util_wlcalib_config.wl_clean,
351 crires_util_wlcalib_config.wl_xclimit,
352 crires_util_wlcalib_config.use_ppm,
353 (i+1==crires_util_wlcalib_config.display),
354 crires_util_wlcalib_config.first_plotted_line,
355 crires_util_wlcalib_config.last_plotted_line,
356 &((crires_util_wlcalib_config.qc_wlxc)[i]),
357 NULL)) == NULL) {
358 cpl_msg_error(__func__,
359 "Wavelength calibration failed - use estimate") ;
360 disp_poly = cpl_polynomial_duplicate(phdisp) ;
361 crires_util_wlcalib_config.qc_wlxc[i] = -1.0 ;
362 }
363 cpl_msg_indent_less() ;
364
365 /* Compute the QC parameters */
366 crires_util_wlcalib_config.qc_wlcent[i] =
367 cpl_polynomial_eval_1d(disp_poly, (double)512, NULL) ;
368 crires_util_wlcalib_config.qc_wldisp[i] =
369 (cpl_polynomial_eval_1d(disp_poly, (double)1024, NULL) -
370 cpl_polynomial_eval_1d(disp_poly, (double)1, NULL)) / 1023 ;
371
372 /* Plot the result */
373 if (crires_util_wlcalib_config.display==i+1) {
374 /* Compute the solution from the passed associated lines if passed*/
375 poly_sol = NULL ;
376 if (crires_util_wlcalib_config.lines != NULL &&
377 crires_util_wlcalib_config.lines[0] != (char)0) {
378 lines_biv =
379 cpl_bivector_read((char*)crires_util_wlcalib_config.lines);
380 if ((lines_biv != NULL) &&
381 (cpl_bivector_get_size(lines_biv)>crires_util_wlcalib_config.degree)) {
382 poly_sol = cpl_polynomial_new(1);
383 samppos = cpl_matrix_wrap(1,
384 cpl_bivector_get_size(lines_biv),
385 cpl_bivector_get_x_data(lines_biv)) ;
386 mindeg = 1 ;
387 maxdeg = (cpl_size)crires_util_wlcalib_config.degree ;
388 cpl_polynomial_fit(poly_sol,
389 samppos, NULL,
390 cpl_bivector_get_y(lines_biv),
391 NULL, CPL_FALSE,
392 &mindeg,
393 &maxdeg) ;
394 cpl_matrix_unwrap(samppos) ;
395 }
396 if (lines_biv != NULL) cpl_bivector_delete(lines_biv) ;
397 }
398 irplib_wlxcorr_plot_solution(phdisp, disp_poly, poly_sol, 1, 1024);
399 if (poly_sol != NULL) {
400 real_sol = irplib_wlxcorr_gen_spc_table(spec, cat_biv,
401 crires_util_wlcalib_config.slitw,
402 crires_util_wlcalib_config.fwhm,
403 phdisp, poly_sol) ;
404 irplib_wlxcorr_plot_spc_table(real_sol, "Real",
405 crires_util_wlcalib_config.first_plotted_line,
406 crires_util_wlcalib_config.last_plotted_line) ;
407 cpl_table_delete(real_sol) ;
408 }
409 if (poly_sol != NULL) cpl_polynomial_delete(poly_sol) ;
410 }
411
412 /* Compute the products */
413 wl_infos[i] = irplib_wlxcorr_gen_spc_table(spec, cat_biv,
414 crires_util_wlcalib_config.slitw,
415 crires_util_wlcalib_config.fwhm,
416 phdisp, disp_poly) ;
417
418 /* Free */
419 cpl_vector_delete(spec) ;
420 cpl_polynomial_delete(phdisp) ;
421
422 /* Create the table */
423 if (crires_util_wlcalib_config.qc_wlxc[i] > 0)
424 spec_pos = crires_get_y_spec_position(fname, i+1) ;
425 else
426 spec_pos = -1 ;
427 wl_tab[i] = crires_wlcalib_gen_wltab_one(
428 (const cpl_polynomial *)disp_poly,
429 spec_pos,
430 crires_util_wlcalib_config.qc_wlxc[i]) ;
431 cpl_polynomial_delete(disp_poly) ;
432 }
433 cpl_bivector_delete(cat_biv) ;
434
435 /* Reconstruct chips in windowing mode using detector 2 */
436 if (crires_util_wlcalib_config.win_mode == 1) {
437 if (wl_tab[1] != NULL) {
438 wl_tab[0] = cpl_table_duplicate(wl_tab[1]) ;
439 cpl_table_set_size(wl_tab[0], 0) ;
440 wl_tab[CRIRES_NB_DETECTORS-1] = cpl_table_duplicate(wl_tab[0]) ;
441 }
442 if (wl_infos[1] != NULL) {
443 wl_infos[0] = cpl_table_duplicate(wl_infos[1]) ;
444 cpl_table_set_size(wl_infos[0], 0) ;
445 wl_infos[CRIRES_NB_DETECTORS-1] = cpl_table_duplicate(wl_infos[0]) ;
446 }
447 }
448
449 /* Create the Map */
450 if ((wl_map = crires_wlcalib_gen_wlmap((const cpl_table **)wl_tab))
451 == NULL) {
452 cpl_msg_error(__func__, "Cannot create WL Map") ;
453 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
454 if (wl_tab[i] != NULL) cpl_table_delete(wl_tab[i]) ;
455 if (wl_infos[i] != NULL) cpl_table_delete(wl_infos[i]) ;
456 }
457 return -1 ;
458 }
459
460 /* Save the result */
461 cpl_msg_info(__func__, "Save the products") ;
462 cpl_msg_indent_more() ;
463 if (crires_util_wlcalib_save(wl_map, (const cpl_table **)wl_tab,
464 (const cpl_table **)wl_infos, parlist, frameset) == -1) {
465 cpl_msg_error(__func__, "Cannot save products");
466 cpl_msg_indent_less() ;
467 cpl_imagelist_delete(wl_map) ;
468 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
469 if (wl_tab[i] != NULL) cpl_table_delete(wl_tab[i]) ;
470 if (wl_infos[i] != NULL) cpl_table_delete(wl_infos[i]) ;
471 }
472 return -1 ;
473 }
474 cpl_msg_indent_less() ;
475 cpl_imagelist_delete(wl_map) ;
476 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
477 if (wl_tab[i] != NULL) cpl_table_delete(wl_tab[i]) ;
478 if (wl_infos[i] != NULL) cpl_table_delete(wl_infos[i]) ;
479 }
480
481 /* Return */
482 if (cpl_error_get_code()) return -1 ;
483 else return 0 ;
484}
485
486/*----------------------------------------------------------------------------*/
496/*----------------------------------------------------------------------------*/
497static int crires_util_wlcalib_save(
498 const cpl_imagelist * ilist,
499 const cpl_table ** tab,
500 const cpl_table ** xctab,
501 const cpl_parameterlist * parlist,
502 cpl_frameset * set)
503{
504 cpl_propertylist ** qclists ;
505 const cpl_frame * ref_frame ;
506 cpl_propertylist * inputlist ;
507 const char * recipe_name = "crires_util_wlcalib" ;
508 int i ;
509
510 /* Get the reference frame */
511 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
512
513 /* Create the QC lists */
514 qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
515 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
516 qclists[i] = cpl_propertylist_new() ;
517 cpl_propertylist_append_double(qclists[i], "ESO QC CENTWL",
518 crires_util_wlcalib_config.qc_wlcent[i]) ;
519 cpl_propertylist_append_double(qclists[i], "ESO QC DISPWL",
520 crires_util_wlcalib_config.qc_wldisp[i]) ;
521 cpl_propertylist_append_double(qclists[i], "ESO QC XCORR",
522 crires_util_wlcalib_config.qc_wlxc[i]) ;
523
524 /* Propagate some keywords from input raw frame extensions */
525 inputlist = cpl_propertylist_load_regexp(
526 cpl_frame_get_filename(ref_frame), i+1,
527 CRIRES_HEADER_EXT_FORWARD, 0) ;
528 cpl_propertylist_copy_property_regexp(qclists[i], inputlist,
529 CRIRES_HEADER_EXT_FORWARD, 0) ;
530 cpl_propertylist_delete(inputlist) ;
531 }
532
533 /* Write the image */
534 crires_image_save(set,
535 parlist,
536 set,
537 ilist,
538 recipe_name,
539 CRIRES_WL_MAP_IMA,
540 CRIRES_PROTYPE_WL_MAP,
541 crires_util_wlcalib_config.period,
542 NULL,
543 (const cpl_propertylist **)qclists,
544 PACKAGE "/" PACKAGE_VERSION,
545 "crires_util_wlcalib_ima.fits") ;
546
547 /* Write the table */
548 crires_table_save(set,
549 parlist,
550 set,
551 tab,
552 recipe_name,
553 CRIRES_CALPRO_WAVE,
554 CRIRES_PROTYPE_WL_POLY,
555 NULL,
556 (const cpl_propertylist **)qclists,
557 PACKAGE "/" PACKAGE_VERSION,
558 "crires_util_wlcalib_tab.fits") ;
559
560 if (xctab[0] != NULL) {
561 /* Write the table */
562 crires_table_save(set,
563 parlist,
564 set,
565 xctab,
566 recipe_name,
567 CRIRES_WL_XCORR_TAB,
568 CRIRES_PROTYPE_XCORR,
569 NULL,
570 (const cpl_propertylist **)qclists,
571 PACKAGE "/" PACKAGE_VERSION,
572 "crires_util_wlcalib_xctab.fits") ;
573 }
574
575 /* Free and return */
576 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
577 cpl_propertylist_delete(qclists[i]) ;
578 }
579 cpl_free(qclists) ;
580 return 0;
581}