37 #include "crires_recipe.h"
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"
49 #define RECIPE_STRING "crires_spec_wavecal"
55 static int crires_spec_wavecal_save(
const cpl_imagelist *,
56 const cpl_imagelist *,
const cpl_table **,
const cpl_parameterlist *,
59 static 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"
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" ;
83 CRIRES_RECIPE_DEFINE(crires_spec_wavecal,
85 CRIRES_PARAM_DISPLAY |
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 |
97 CRIRES_PARAM_WL_CLEAN,
98 "Wavelength calibration",
99 crires_spec_wavecal_description) ;
107 double wstart[CRIRES_NB_DETECTORS] ;
108 double wstop[CRIRES_NB_DETECTORS] ;
111 const char * wl_ypos_c1 ;
112 const char * wl_ypos_c2 ;
113 const char * wl_ypos_c3 ;
114 const char * wl_ypos_c4 ;
126 crires_illum_period period ;
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 ;
148 static int crires_spec_wavecal(
149 cpl_frameset * frameset,
150 const cpl_parameterlist * parlist)
153 const char * wl_ypos ;
154 cpl_frameset * rawframes ;
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 ;
168 cpl_table * wave_tab[CRIRES_NB_DETECTORS] ;
169 cpl_imagelist * wl_map ;
170 cpl_imagelist * wl_map_model ;
171 cpl_vector * wave_ypos ;
176 setlocale(LC_NUMERIC,
"C");
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 ;
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 ;
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){
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) ;
235 if (crires_dfs_set_groups(frameset,
"crires_spec_wavecal")) {
236 cpl_msg_error(__func__,
"Cannot identify RAW and CALIB frames") ;
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) ;
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 ;
263 cpl_msg_error(__func__,
"No raw frame in input") ;
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) ;
277 crires_display_detector_illum(crires_spec_wavecal_config.period) ;
281 fname = cpl_frame_get_filename(cpl_frameset_get_position(rawframes,0)) ;
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()) {
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() ;
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 ;
312 if (!strcmp(wl_ypos,
"")) {
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) ;
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,
329 cpl_msg_warning(__func__,
330 "Cannot read the Y positions from file %s",
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);
344 if (crires_spec_wavecal_config.mode == 1) {
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],
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) {
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],
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) {
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],
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])) ;
414 cpl_msg_indent_less() ;
415 cpl_vector_delete(wave_ypos) ;
417 cpl_msg_indent_less() ;
420 if ((wl_map = crires_wlcalib_gen_wlmap((
const cpl_table **)wave_tab))
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]);
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),
435 crires_spec_wavecal_config.qc_wldisp[i] =
436 ((cpl_image_get(cpl_imagelist_get(wl_map, i), 1024,
438 (cpl_image_get(cpl_imagelist_get(wl_map, i), 1,
441 crires_spec_wavecal_config.qc_wlxc[i] =
442 crires_wlcalib_get_better_xc(wave_tab[i]) ;
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") ;
455 cpl_msg_indent_less() ;
457 wl_map_model = NULL ;
459 cpl_frameset_delete(rawframes) ;
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() ;
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() ;
481 if (cpl_error_get_code())
return -1 ;
496 static 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,
503 cpl_propertylist ** qclists ;
504 const cpl_frame * ref_frame ;
505 cpl_propertylist * inputlist ;
506 const char * recipe_name =
"crires_spec_wavecal" ;
510 ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
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]) ;
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) ;
539 crires_image_save(set,
545 CRIRES_PROTYPE_WL_MAP,
546 crires_spec_wavecal_config.period,
548 (
const cpl_propertylist **)qclists,
549 PACKAGE
"/" PACKAGE_VERSION,
550 "crires_spec_wavecal_ima.fits") ;
552 if (ilist_model != NULL) {
554 crires_image_save(set,
559 CRIRES_WL_MAP_MODEL_IMA,
560 CRIRES_PROTYPE_WL_MAP,
561 crires_spec_wavecal_config.period,
563 (
const cpl_propertylist **)qclists,
564 PACKAGE
"/" PACKAGE_VERSION,
565 "crires_spec_wavecal_ima_model.fits") ;
569 crires_table_save(set,
575 CRIRES_PROTYPE_WL_POLY,
577 (
const cpl_propertylist **)qclists,
578 PACKAGE
"/" PACKAGE_VERSION,
579 "crires_spec_wavecal_tab.fits") ;
582 for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
583 cpl_propertylist_delete(qclists[i]) ;