CRIRES Pipeline Reference Manual 2.3.19
crires_spec_wavecal.c
1/* $Id: crires_spec_wavecal.c,v 1.75 2012-10-09 08:18:01 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-10-09 08:18:01 $
24 * $Revision: 1.75 $
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 "crires_combine.h"
40#include "crires_wlcalib.h"
41#include "crires_extract.h"
42#include "crires_model_kernel.h"
43#include "irplib_utils.h"
44
45/*-----------------------------------------------------------------------------
46 Define
47 -----------------------------------------------------------------------------*/
48
49#define RECIPE_STRING "crires_spec_wavecal"
50
51/*-----------------------------------------------------------------------------
52 Functions prototypes
53 -----------------------------------------------------------------------------*/
54
55static int crires_spec_wavecal_save(const cpl_imagelist *,
56 const cpl_imagelist *, const cpl_table **, const cpl_parameterlist *,
57 cpl_frameset *) ;
58
59static char crires_spec_wavecal_description[] =
60"crires_spec_wavecal -- Wavelength calibration\n"
61"The files listed in the Set Of Frames (sof-file) must be tagged:\n"
62"raw-file.fits "CRIRES_SPEC_WAVECAL_SKY_RAW" or\n"
63"raw-file.fits "CRIRES_SPEC_WAVECAL_LAMP_RAW" or\n"
64"raw-file.fits "CRIRES_SPEC_WAVECAL_ABS_RAW" or\n"
65"flat-file.fits "CRIRES_CALPRO_FLAT" or\n"
66"bpm-file.fits "CRIRES_CALPRO_BPM" or\n"
67"dark-file.fits "CRIRES_CALPRO_DARK" or\n"
68"detlin-file.fits "CRIRES_CALPRO_COEFFS_CUBE" or\n"
69"catalog-file.fits "CRIRES_CALPRO_THAR_CAT" or\n"
70"catalog-file.fits "CRIRES_CALPRO_OH_CAT" or\n"
71"catalog-file.fits "CRIRES_CALPRO_HITRAN_CAT" or\n"
72"ypos-file.fits "CRIRES_CALPRO_THAR_POS" or\n"
73"model-config-file.fits "CRIRES_CALPRO_MODEL_CONFIG".\n"
74"\n"
75"This recipe produces 3 files:\n"
76"First product: the image with the wavelength values.\n"
77" (PRO TYPE = "CRIRES_PROTYPE_WL_MAP")\n"
78"Second product: the image with the wavelength values from the model.\n"
79" (PRO TYPE = "CRIRES_PROTYPE_WL_MAP")\n"
80"Third product: the table with the wavelength polynomial coefficients.\n"
81" (PRO TYPE = "CRIRES_PROTYPE_WL_POLY")\n" ;
82
83CRIRES_RECIPE_DEFINE(crires_spec_wavecal,
84 CRIRES_PARAM_WAVES |
85 CRIRES_PARAM_DISPLAY |
86 CRIRES_PARAM_WL_LOG |
87 CRIRES_PARAM_WL_NOLIMIT |
88 CRIRES_PARAM_WL_ERROR |
89 CRIRES_PARAM_XC_LIMIT |
90 CRIRES_PARAM_WL_NBSAMPLES |
91 CRIRES_PARAM_Y_POS_CHIP1 |
92 CRIRES_PARAM_Y_POS_CHIP2 |
93 CRIRES_PARAM_Y_POS_CHIP3 |
94 CRIRES_PARAM_Y_POS_CHIP4 |
95 CRIRES_PARAM_Y_WIDTH |
96 CRIRES_PARAM_DEGREE |
97 CRIRES_PARAM_WL_CLEAN,
98 "Wavelength calibration",
99 crires_spec_wavecal_description) ;
100
101/*-----------------------------------------------------------------------------
102 Static variables
103 -----------------------------------------------------------------------------*/
104
105static struct {
106 /* Inputs */
107 double wstart[CRIRES_NB_DETECTORS] ;
108 double wstop[CRIRES_NB_DETECTORS] ;
109 int wl_nolimit ;
110 int wl_log ;
111 const char * wl_ypos_c1 ;
112 const char * wl_ypos_c2 ;
113 const char * wl_ypos_c3 ;
114 const char * wl_ypos_c4 ;
115 int wl_width ;
116 double wl_fwhm ;
117 double wl_slitw ;
118 int wl_degree ;
119 double wl_err ;
120 int wl_samples ;
121 int wl_clean ;
122 double wl_xclimit ;
123 int wl_ppm ;
124 int display ;
125 /* Outputs */
126 crires_illum_period period ;
127 int mode ;
128 double qc_wlxc[CRIRES_NB_DETECTORS] ;
129 double qc_wlcent[CRIRES_NB_DETECTORS] ;
130 double qc_wldisp[CRIRES_NB_DETECTORS] ;
131 double qc_lines_flux[CRIRES_NB_DETECTORS] ;
132 double qc_fwhm[CRIRES_NB_DETECTORS] ;
133 double qc_rpower[CRIRES_NB_DETECTORS] ;
134} crires_spec_wavecal_config ;
135
136/*-----------------------------------------------------------------------------
137 Functions code
138 -----------------------------------------------------------------------------*/
139
140/*----------------------------------------------------------------------------*/
147/*----------------------------------------------------------------------------*/
148static int crires_spec_wavecal(
149 cpl_frameset * frameset,
150 const cpl_parameterlist * parlist)
151{
152 const char * sval ;
153 const char * wl_ypos ;
154 cpl_frameset * rawframes ;
155 const char * fname ;
156 const char * flat ;
157 const char * dark ;
158 const char * bpm ;
159 const char * detlin ;
160 const char * thar_cat ;
161 const char * n2o_cat ;
162 const char * oh_cat ;
163 const char * hitran_cat ;
164 const char * cfg_model ;
165 const char * thar_positions ;
166 cpl_propertylist * plist ;
167 double wmin, wmax ;
168 cpl_table * wave_tab[CRIRES_NB_DETECTORS] ;
169 cpl_imagelist * wl_map ;
170 cpl_imagelist * wl_map_model ;
171 cpl_vector * wave_ypos ;
172 int pix ;
173 int i, j ;
174
175 /* Needed for sscanf() */
176 setlocale(LC_NUMERIC, "C");
177
178 /* Initialise */
179 rawframes = NULL ;
180 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
181 crires_spec_wavecal_config.qc_wlxc[i] = -1.0 ;
182 crires_spec_wavecal_config.qc_wlcent[i] = -1.0 ;
183 crires_spec_wavecal_config.qc_wldisp[i] = -1.0 ;
184 crires_spec_wavecal_config.qc_lines_flux[i] = -1.0 ;
185 crires_spec_wavecal_config.qc_fwhm[i] = -1.0 ;
186 crires_spec_wavecal_config.qc_rpower[i] = -1.0 ;
187 }
188 crires_spec_wavecal_config.wl_ppm = 0 ;
189 crires_spec_wavecal_config.wl_slitw = 2.0 ;
190 crires_spec_wavecal_config.wl_fwhm = 2.0 ;
191
192 /* Retrieve input parameters */
193
194 sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
195 CRIRES_PARAM_WAVES) ;
196 if (sscanf(sval, "%lg,%lg,%lg,%lg,%lg,%lg,%lg,%lg",
197 &crires_spec_wavecal_config.wstart[0],
198 &crires_spec_wavecal_config.wstop[0],
199 &crires_spec_wavecal_config.wstart[1],
200 &crires_spec_wavecal_config.wstop[1],
201 &crires_spec_wavecal_config.wstart[2],
202 &crires_spec_wavecal_config.wstop[2],
203 &crires_spec_wavecal_config.wstart[3],
204 &crires_spec_wavecal_config.wstop[3])!=2*CRIRES_NB_DETECTORS){
205 return -1 ;
206 }
207 crires_spec_wavecal_config.display = crires_parameterlist_get_int(parlist,
208 RECIPE_STRING, CRIRES_PARAM_DISPLAY) ;
209 crires_spec_wavecal_config.wl_log = crires_parameterlist_get_bool(parlist,
210 RECIPE_STRING, CRIRES_PARAM_WL_LOG) ;
211 crires_spec_wavecal_config.wl_nolimit = crires_parameterlist_get_bool(
212 parlist, RECIPE_STRING, CRIRES_PARAM_WL_NOLIMIT) ;
213 crires_spec_wavecal_config.wl_degree = crires_parameterlist_get_int(parlist,
214 RECIPE_STRING, CRIRES_PARAM_DEGREE) ;
215 crires_spec_wavecal_config.wl_err = crires_parameterlist_get_double(parlist,
216 RECIPE_STRING, CRIRES_PARAM_WL_ERROR) ;
217 crires_spec_wavecal_config.wl_xclimit = crires_parameterlist_get_double(
218 parlist, RECIPE_STRING, CRIRES_PARAM_XC_LIMIT) ;
219 crires_spec_wavecal_config.wl_ypos_c1=crires_parameterlist_get_string(
220 parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP1) ;
221 crires_spec_wavecal_config.wl_ypos_c2=crires_parameterlist_get_string(
222 parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP2) ;
223 crires_spec_wavecal_config.wl_ypos_c3=crires_parameterlist_get_string(
224 parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP3) ;
225 crires_spec_wavecal_config.wl_ypos_c4=crires_parameterlist_get_string(
226 parlist, RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP4) ;
227 crires_spec_wavecal_config.wl_width= crires_parameterlist_get_int(parlist,
228 RECIPE_STRING, CRIRES_PARAM_Y_WIDTH) ;
229 crires_spec_wavecal_config.wl_samples = crires_parameterlist_get_int(
230 parlist, RECIPE_STRING, CRIRES_PARAM_WL_NBSAMPLES) ;
231 crires_spec_wavecal_config.wl_clean = crires_parameterlist_get_bool(parlist,
232 RECIPE_STRING, CRIRES_PARAM_WL_CLEAN) ;
233
234 /* Identify the RAW and CALIB frames in the input frameset */
235 if (crires_dfs_set_groups(frameset, "crires_spec_wavecal")) {
236 cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
237 return -1 ;
238 }
239
240 /* Retrieve calibration data */
241 flat = crires_extract_filename(frameset, CRIRES_CALPRO_FLAT) ;
242 dark = crires_extract_filename(frameset, CRIRES_CALPRO_DARK) ;
243 bpm = crires_extract_filename(frameset, CRIRES_CALPRO_BPM) ;
244 detlin = crires_extract_filename(frameset, CRIRES_CALPRO_COEFFS_CUBE) ;
245 thar_cat = crires_extract_filename(frameset, CRIRES_CALPRO_THAR_CAT) ;
246 n2o_cat = crires_extract_filename(frameset, CRIRES_CALPRO_N2O_CAT) ;
247 oh_cat = crires_extract_filename(frameset, CRIRES_CALPRO_OH_CAT) ;
248 hitran_cat = crires_extract_filename(frameset, CRIRES_CALPRO_HITRAN_CAT) ;
249 cfg_model = crires_extract_filename(frameset, CRIRES_CALPRO_MODEL_CONFIG) ;
250 thar_positions = crires_extract_filename(frameset, CRIRES_CALPRO_THAR_POS) ;
251
252 /* Retrieve raw frames */
253 if ((rawframes = crires_extract_frameset(frameset,
254 CRIRES_SPEC_WAVECAL_SKY_RAW)) != NULL) {
255 crires_spec_wavecal_config.mode = 1 ;
256 } else if ((rawframes = crires_extract_frameset(frameset,
257 CRIRES_SPEC_WAVECAL_LAMP_RAW)) != NULL) {
258 crires_spec_wavecal_config.mode = 2 ;
259 } else if ((rawframes = crires_extract_frameset(frameset,
260 CRIRES_SPEC_WAVECAL_ABS_RAW)) != NULL) {
261 crires_spec_wavecal_config.mode = 3 ;
262 } else {
263 cpl_msg_error(__func__, "No raw frame in input") ;
264 return -1 ;
265 }
266
267 /* Get the detector illumination period */
268 crires_spec_wavecal_config.period =
269 crires_get_detector_illum_period(
270 cpl_frame_get_filename(cpl_frameset_get_position(rawframes, 0))) ;
271 if (crires_spec_wavecal_config.period == CRIRES_ILLUM_UNKNOWN) {
272 cpl_msg_error(__func__,
273 "Cannot determine the detector illumination period") ;
274 cpl_frameset_delete(rawframes) ;
275 return -1 ;
276 } else {
277 crires_display_detector_illum(crires_spec_wavecal_config.period) ;
278 }
279
280 /* Reduce the first raw frame */
281 fname = cpl_frame_get_filename(cpl_frameset_get_position(rawframes,0)) ;
282
283 /* Get the Minimum and Maximum wavelengths */
284 if (crires_spec_wavecal_config.wl_nolimit == 0) {
285 plist = cpl_propertylist_load(fname, 0) ;
286 wmin = crires_pfits_get_wlen_min(plist) ;
287 wmax = crires_pfits_get_wlen_max(plist) ;
288 cpl_propertylist_delete(plist) ;
289 if (cpl_error_get_code()) {
290 wmin = wmax = -1.0 ;
291 cpl_error_reset() ;
292 }
293 } else {
294 wmin = wmax = -1.0 ;
295 }
296
297 /* Wavelength calibration */
298 cpl_msg_info(__func__, "Apply the Wavelength Calibration") ;
299 cpl_msg_indent_more() ;
300 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
301 cpl_msg_info(__func__, "Calibrate chip number %d", i+1) ;
302 cpl_msg_indent_more() ;
303
304 /* Where Compute the wavelength from ? */
305 wl_ypos = "" ;
306 if (i+1 == 1) wl_ypos = crires_spec_wavecal_config.wl_ypos_c1 ;
307 if (i+1 == 2) wl_ypos = crires_spec_wavecal_config.wl_ypos_c2 ;
308 if (i+1 == 3) wl_ypos = crires_spec_wavecal_config.wl_ypos_c3 ;
309 if (i+1 == 4) wl_ypos = crires_spec_wavecal_config.wl_ypos_c4 ;
310
311 /* Try to parse the user specified positions */
312 if (!strcmp(wl_ypos, "")) {
313 wave_ypos = NULL ;
314 } else {
315 cpl_msg_info(__func__,
316 "Use the Y positions provided on the command line") ;
317 if ((wave_ypos = crires_parse_y_positions(wl_ypos)) == NULL) {
318 cpl_msg_warning(__func__,
319 "Cannot parse the y_positions value : %s", wl_ypos) ;
320 }
321 }
322
323 /* Otherwise use passed calibration file */
324 if (wave_ypos == NULL && thar_positions != NULL) {
325 cpl_msg_info(__func__,
326 "Use the Y positions provided in the FITS file") ;
327 if ((wave_ypos = crires_read_y_positions(thar_positions,
328 i+1)) == NULL) {
329 cpl_msg_warning(__func__,
330 "Cannot read the Y positions from file %s",
331 thar_positions) ;
332 }
333 }
334
335 /* Try to detect the positions */
336 if (wave_ypos == NULL) {
337 cpl_msg_info(__func__,
338 "Try an automatic detection of the Y positions") ;
339 wave_ypos = crires_wlcalib_detect_wave_ypos(fname,
340 crires_spec_wavecal_config.period, i+1);
341 }
342
343 /* Check the Mode */
344 if (crires_spec_wavecal_config.mode == 1) {
345 /* Calibrate from the sky */
346 cpl_msg_info(__func__,"Get the calibration from the oh/hitran sky");
347 wave_tab[i] = crires_wlcalib_sky(fname,
348 crires_spec_wavecal_config.period,
349 oh_cat, hitran_cat, crires_spec_wavecal_config.wl_log,
350 flat, dark, bpm, detlin,
351 crires_spec_wavecal_config.wstart[i],
352 crires_spec_wavecal_config.wstop[i],
353 wmin, wmax, i+1,
354 wave_ypos,
355 crires_spec_wavecal_config.wl_width,
356 crires_spec_wavecal_config.wl_degree,
357 crires_spec_wavecal_config.wl_slitw,
358 crires_spec_wavecal_config.wl_fwhm,
359 crires_spec_wavecal_config.wl_err,
360 crires_spec_wavecal_config.wl_samples,
361 crires_spec_wavecal_config.wl_clean,
362 crires_spec_wavecal_config.wl_xclimit,
363 crires_spec_wavecal_config.wl_ppm,
364 (i+1==crires_spec_wavecal_config.display)) ;
365 } else if (crires_spec_wavecal_config.mode == 2) {
366 /* Calibrate from the lamp */
367 cpl_msg_info(__func__, "Get the calibration from the thar lamp") ;
368 wave_tab[i] = crires_wlcalib_lamp(fname,
369 crires_spec_wavecal_config.period,
370 thar_cat, crires_spec_wavecal_config.wl_log,
371 flat, dark, bpm, detlin,
372 crires_spec_wavecal_config.wstart[i],
373 crires_spec_wavecal_config.wstop[i],
374 wmin, wmax, i+1,
375 wave_ypos,
376 crires_spec_wavecal_config.wl_width,
377 crires_spec_wavecal_config.wl_degree,
378 crires_spec_wavecal_config.wl_slitw,
379 crires_spec_wavecal_config.wl_fwhm,
380 crires_spec_wavecal_config.wl_err,
381 crires_spec_wavecal_config.wl_samples,
382 crires_spec_wavecal_config.wl_clean,
383 crires_spec_wavecal_config.wl_xclimit,
384 crires_spec_wavecal_config.wl_ppm,
385 (i+1==crires_spec_wavecal_config.display),
386 &(crires_spec_wavecal_config.qc_lines_flux[i]),
387 &(crires_spec_wavecal_config.qc_fwhm[i]),
388 &(crires_spec_wavecal_config.qc_rpower[i])) ;
389 } else if (crires_spec_wavecal_config.mode == 3) {
390 /* Calibrate from the gas cell */
391 cpl_msg_info(__func__, "Get the calibration from the n2o gas cell");
392 wave_tab[i] = crires_wlcalib_lamp(fname,
393 crires_spec_wavecal_config.period,
394 n2o_cat, crires_spec_wavecal_config.wl_log,
395 flat, dark, bpm, detlin,
396 crires_spec_wavecal_config.wstart[i],
397 crires_spec_wavecal_config.wstop[i],
398 wmin, wmax, i+1,
399 wave_ypos,
400 crires_spec_wavecal_config.wl_width,
401 crires_spec_wavecal_config.wl_degree,
402 crires_spec_wavecal_config.wl_slitw,
403 crires_spec_wavecal_config.wl_fwhm,
404 crires_spec_wavecal_config.wl_err,
405 crires_spec_wavecal_config.wl_samples,
406 crires_spec_wavecal_config.wl_clean,
407 crires_spec_wavecal_config.wl_xclimit,
408 crires_spec_wavecal_config.wl_ppm,
409 (i+1==crires_spec_wavecal_config.display),
410 &(crires_spec_wavecal_config.qc_lines_flux[i]),
411 &(crires_spec_wavecal_config.qc_fwhm[i]),
412 &(crires_spec_wavecal_config.qc_rpower[i])) ;
413 }
414 cpl_msg_indent_less() ;
415 cpl_vector_delete(wave_ypos) ;
416 }
417 cpl_msg_indent_less() ;
418
419 /* Create the wave map */
420 if ((wl_map = crires_wlcalib_gen_wlmap((const cpl_table **)wave_tab))
421 == NULL) {
422 cpl_msg_error(__func__, "Cannot compute the Wavelength Map") ;
423 cpl_frameset_delete(rawframes) ;
424 for (j=0 ; j<CRIRES_NB_DETECTORS ; j++) {
425 if (wave_tab[j] != NULL) cpl_table_delete(wave_tab[j]);
426 }
427 return -1 ;
428 }
429
430 /* Compute the QC parameters */
431 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
432 crires_spec_wavecal_config.qc_wlcent[i] =
433 cpl_image_get(cpl_imagelist_get(wl_map, i),
434 512, 256, &pix) ;
435 crires_spec_wavecal_config.qc_wldisp[i] =
436 ((cpl_image_get(cpl_imagelist_get(wl_map, i), 1024,
437 256, &pix)) -
438 (cpl_image_get(cpl_imagelist_get(wl_map, i), 1,
439 256, &pix)))
440 / 1023 ;
441 crires_spec_wavecal_config.qc_wlxc[i] =
442 crires_wlcalib_get_better_xc(wave_tab[i]) ;
443 }
444
445 /* Get the wl map from the model */
446 if ((cfg_model != NULL) && (!crires_model_off()) &&
447 (crires_model_config_check(cfg_model, fname) == 0)) {
448 cpl_msg_info(__func__, "Call the model to get the wavelength map") ;
449 cpl_msg_indent_more() ;
450 wl_map_model = crires_model_wavpix(fname, cfg_model, -1) ;
451 if (wl_map_model == NULL) {
452 cpl_msg_warning(__func__, "Model function returns NULL") ;
453 cpl_error_reset() ;
454 }
455 cpl_msg_indent_less() ;
456 } else {
457 wl_map_model = NULL ;
458 }
459 cpl_frameset_delete(rawframes) ;
460
461 /* Save the product */
462 cpl_msg_info(__func__, "Save the product") ;
463 cpl_msg_indent_more() ;
464 if (crires_spec_wavecal_save(wl_map, wl_map_model,
465 (const cpl_table **)wave_tab, parlist, frameset)) {
466 cpl_msg_error(__func__, "Cannot save the product") ;
467 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++)
468 if (wave_tab[i] != NULL) cpl_table_delete(wave_tab[i]);
469 cpl_imagelist_delete(wl_map) ;
470 if (wl_map_model) cpl_imagelist_delete(wl_map_model) ;
471 cpl_msg_indent_less() ;
472 return -1 ;
473 }
474 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++)
475 if (wave_tab[i] != NULL) cpl_table_delete(wave_tab[i]);
476 cpl_imagelist_delete(wl_map) ;
477 if (wl_map_model) cpl_imagelist_delete(wl_map_model) ;
478 cpl_msg_indent_less() ;
479
480 /* Return */
481 if (cpl_error_get_code()) return -1 ;
482 else return 0 ;
483}
484
485/*----------------------------------------------------------------------------*/
495/*----------------------------------------------------------------------------*/
496static int crires_spec_wavecal_save(
497 const cpl_imagelist * ilist,
498 const cpl_imagelist * ilist_model,
499 const cpl_table ** wl_tab,
500 const cpl_parameterlist * parlist,
501 cpl_frameset * set)
502{
503 cpl_propertylist ** qclists ;
504 const cpl_frame * ref_frame ;
505 cpl_propertylist * inputlist ;
506 const char * recipe_name = "crires_spec_wavecal" ;
507 int i ;
508
509 /* Get the reference frame */
510 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
511
512 /* Create the QC lists */
513 qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
514 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
515 qclists[i] = cpl_propertylist_new() ;
516 cpl_propertylist_append_double(qclists[i], "ESO QC CENTWL",
517 crires_spec_wavecal_config.qc_wlcent[i]) ;
518 cpl_propertylist_append_double(qclists[i], "ESO QC DISPWL",
519 crires_spec_wavecal_config.qc_wldisp[i]) ;
520 cpl_propertylist_append_double(qclists[i], "ESO QC XCORR",
521 crires_spec_wavecal_config.qc_wlxc[i]) ;
522 cpl_propertylist_append_double(qclists[i], "ESO QC LINES FLUX",
523 crires_spec_wavecal_config.qc_lines_flux[i]) ;
524 cpl_propertylist_append_double(qclists[i], "ESO QC FWHM MED",
525 crires_spec_wavecal_config.qc_fwhm[i]) ;
526 cpl_propertylist_append_double(qclists[i], "ESO QC RESOL MED",
527 crires_spec_wavecal_config.qc_rpower[i]) ;
528
529 /* Propagate some keywords from input raw frame extensions */
530 inputlist = cpl_propertylist_load_regexp(
531 cpl_frame_get_filename(ref_frame), i+1,
532 CRIRES_HEADER_EXT_FORWARD, 0) ;
533 cpl_propertylist_copy_property_regexp(qclists[i], inputlist,
534 CRIRES_HEADER_EXT_FORWARD, 0) ;
535 cpl_propertylist_delete(inputlist) ;
536 }
537
538 /* Write the image */
539 crires_image_save(set,
540 parlist,
541 set,
542 ilist,
543 recipe_name,
544 CRIRES_WL_MAP_IMA,
545 CRIRES_PROTYPE_WL_MAP,
546 crires_spec_wavecal_config.period,
547 NULL,
548 (const cpl_propertylist **)qclists,
549 PACKAGE "/" PACKAGE_VERSION,
550 "crires_spec_wavecal_ima.fits") ;
551
552 if (ilist_model != NULL) {
553 /* Write the image */
554 crires_image_save(set,
555 parlist,
556 set,
557 ilist_model,
558 recipe_name,
559 CRIRES_WL_MAP_MODEL_IMA,
560 CRIRES_PROTYPE_WL_MAP,
561 crires_spec_wavecal_config.period,
562 NULL,
563 (const cpl_propertylist **)qclists,
564 PACKAGE "/" PACKAGE_VERSION,
565 "crires_spec_wavecal_ima_model.fits") ;
566 }
567
568 /* Write the table */
569 crires_table_save(set,
570 parlist,
571 set,
572 wl_tab,
573 recipe_name,
574 CRIRES_CALPRO_WAVE,
575 CRIRES_PROTYPE_WL_POLY,
576 NULL,
577 (const cpl_propertylist **)qclists,
578 PACKAGE "/" PACKAGE_VERSION,
579 "crires_spec_wavecal_tab.fits") ;
580
581 /* Free and return */
582 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
583 cpl_propertylist_delete(qclists[i]) ;
584 }
585 cpl_free(qclists) ;
586 return 0;
587}