CRIRES Pipeline Reference Manual  2.3.15
crires_util_extract.c
1 /*
2  * This file is part of the crires Pipeline
3  * Copyright (C) 2002,2003 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 /*-----------------------------------------------------------------------------
25  Includes
26  -----------------------------------------------------------------------------*/
27 
28 #include <locale.h>
29 #include "crires_recipe.h"
30 
31 #include "crires_extract.h"
32 #include "irplib_utils.h"
33 
34 /*-----------------------------------------------------------------------------
35  Define
36  -----------------------------------------------------------------------------*/
37 
38 #define RECIPE_STRING "crires_util_extract"
39 
40 /*-----------------------------------------------------------------------------
41  Functions prototypes
42  -----------------------------------------------------------------------------*/
43 
44 static int crires_util_extract_save(const cpl_table **, const cpl_imagelist *,
45  const cpl_imagelist *, const cpl_parameterlist *, cpl_frameset *) ;
46 
47 static char crires_util_extract_description[] =
48 "This recipe accepts 1 parameter (optionally a 2nd one):\n"
49 "First parameter: the combined image.\n"
50 " (PRO TYPE = "CRIRES_PROTYPE_COMBINED")\n"
51 "Second parameter (optional): the contribution map.\n"
52 " (PRO TYPE = "CRIRES_PROTYPE_CONTRIB")\n"
53 "\n"
54 "This recipe produces 3 files:\n"
55 "First product: the image of the profile of the spectrum\n"
56 " (PRO TYPE = "CRIRES_PROTYPE_PROFILE")\n"
57 "Second product: the table of the extracted spectrum in pixels\n"
58 " (PRO TYPE = "CRIRES_PROTYPE_SPEC_PIX")\n"
59 "Third product: the maps of the background\n"
60 " (PRO TYPE = "CRIRES_PROTYPE_BGD_MAP")\n" ;
61 
62 CRIRES_RECIPE_DEFINE(crires_util_extract,
63  CRIRES_PARAM_DISPLAY |
64  CRIRES_PARAM_EXTR_MODE |
65  CRIRES_PARAM_HOR_SIZE |
66  CRIRES_PARAM_SPEC_HSIZE |
67  CRIRES_PARAM_KAPPA |
68  CRIRES_PARAM_CLOSING_HSIZE |
69  CRIRES_PARAM_CLEAN_RATE |
70  CRIRES_PARAM_TOT_NDIT |
71  CRIRES_PARAM_Y_POS_CHIP1 |
72  CRIRES_PARAM_Y_POS_CHIP2 |
73  CRIRES_PARAM_Y_POS_CHIP3 |
74  CRIRES_PARAM_Y_POS_CHIP4 |
75  CRIRES_PARAM_Y_WIDTH |
76  CRIRES_PARAM_Y_SPEC_ZONE_CHIP1 |
77  CRIRES_PARAM_Y_SPEC_ZONE_CHIP2 |
78  CRIRES_PARAM_Y_SPEC_ZONE_CHIP3 |
79  CRIRES_PARAM_Y_SPEC_ZONE_CHIP4 |
80  CRIRES_PARAM_REJECT,
81  "Spectrum extraction routine",
82  crires_util_extract_description) ;
83 
84 /*-----------------------------------------------------------------------------
85  Static variables
86  -----------------------------------------------------------------------------*/
87 
88 static struct {
89  /* Inputs */
90  /* mode : 1=spec ; 2=lines */
91  int mode ;
92  double kappa ; /* mode = 1 */
93  int closing_hs ; /* mode = 1 */
94  double clean_rate ; /* mode = 1 */
95  double tot_ndit ; /* mode = 1 */
96  int box_hor_size ; /* mode = 1 */
97  int spec_hsize ; /* mode = 1 */
98  const char * y_spec_zone_c1 ;/* mode = 1 */
99  const char * y_spec_zone_c2 ;/* mode = 1 */
100  const char * y_spec_zone_c3 ;/* mode = 1 */
101  const char * y_spec_zone_c4 ;/* mode = 1 */
102  const char * y_pos_c1 ; /* mode = 2 */
103  const char * y_pos_c2 ; /* mode = 2 */
104  const char * y_pos_c3 ; /* mode = 2 */
105  const char * y_pos_c4 ; /* mode = 2 */
106  int y_width ; /* mode = 2 */
107  int rej_right ; /* All modes */
108  int rej_left ; /* All modes */
109  int display ; /* All modes */
110  /* Outputs */
111  int win_mode ;
112  crires_illum_period period ;
113  int qc_specpos[CRIRES_NB_DETECTORS] ;
114  int qc_specwrec[CRIRES_NB_DETECTORS] ;
115  int qc_specwopt[CRIRES_NB_DETECTORS] ;
116  double qc_specoptmed[CRIRES_NB_DETECTORS] ;
117  double qc_s2nmed[CRIRES_NB_DETECTORS] ;
118  double qc_fwhm_comb_pix[CRIRES_NB_DETECTORS] ;
119  double qc_fwhm_comb_as[CRIRES_NB_DETECTORS] ;
120  double qc_fwhm_prof_pix[CRIRES_NB_DETECTORS] ;
121  double qc_fwhm_prof_as[CRIRES_NB_DETECTORS] ;
122  double qc_fwhm_diff[CRIRES_NB_DETECTORS] ;
123 } crires_util_extract_config ;
124 
125 /*-----------------------------------------------------------------------------
126  Functions code
127  -----------------------------------------------------------------------------*/
128 
129 /*----------------------------------------------------------------------------*/
136 /*----------------------------------------------------------------------------*/
137 static int crires_util_extract(
138  cpl_frameset * frameset,
139  const cpl_parameterlist * parlist)
140 {
141  const char * sval ;
142  const char * y_pos ;
143  cpl_imagelist * imlist ;
144  cpl_propertylist * plist ;
145  cpl_imagelist * contrib ;
146  cpl_image * contribution_map ;
147  cpl_frame * fr ;
148  cpl_imagelist * profile ;
149  cpl_image * prof[CRIRES_NB_DETECTORS] ;
150  cpl_imagelist * bgmaps ;
151  cpl_image * bgmap[CRIRES_NB_DETECTORS] ;
152  cpl_table * ext[CRIRES_NB_DETECTORS] ;
153  cpl_vector * ext_vec ;
154  cpl_vector * ypos_vec ;
155  int ly, nexp, starty, stopy, extr_spec_starty,
156  extr_spec_stopy ;
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_extract_config.qc_specpos[i] = -1 ;
165  crires_util_extract_config.qc_specwrec[i] = -1 ;
166  crires_util_extract_config.qc_specwopt[i] = -1 ;
167  crires_util_extract_config.qc_specoptmed[i] = -1.0 ;
168  crires_util_extract_config.qc_s2nmed[i] = -1.0 ;
169  crires_util_extract_config.qc_fwhm_comb_pix[i] = -1.0 ;
170  crires_util_extract_config.qc_fwhm_comb_as[i] = -1.0 ;
171  crires_util_extract_config.qc_fwhm_prof_pix[i] = -1.0 ;
172  crires_util_extract_config.qc_fwhm_prof_as[i] = -1.0 ;
173  crires_util_extract_config.qc_fwhm_diff[i] = -1.0 ;
174  ext[i] = NULL ;
175  prof[i] = NULL ;
176  bgmap[i] = NULL ;
177  }
178  ly = -1 ;
179 
180  /* Retrieve input parameters */
181  crires_util_extract_config.display = crires_parameterlist_get_int(parlist,
182  RECIPE_STRING, CRIRES_PARAM_DISPLAY) ;
183  crires_util_extract_config.mode = crires_parameterlist_get_int(parlist,
184  RECIPE_STRING, CRIRES_PARAM_EXTR_MODE) ;
185  crires_util_extract_config.box_hor_size = crires_parameterlist_get_int(
186  parlist, RECIPE_STRING, CRIRES_PARAM_HOR_SIZE) ;
187  crires_util_extract_config.spec_hsize = crires_parameterlist_get_int(
188  parlist, RECIPE_STRING, CRIRES_PARAM_SPEC_HSIZE) ;
189  crires_util_extract_config.kappa = crires_parameterlist_get_double(
190  parlist, RECIPE_STRING, CRIRES_PARAM_KAPPA) ;
191  crires_util_extract_config.closing_hs = crires_parameterlist_get_int(
192  parlist, RECIPE_STRING, CRIRES_PARAM_CLOSING_HSIZE) ;
193  crires_util_extract_config.clean_rate = crires_parameterlist_get_double(
194  parlist, RECIPE_STRING, CRIRES_PARAM_CLEAN_RATE) ;
195  crires_util_extract_config.tot_ndit = crires_parameterlist_get_double(
196  parlist, RECIPE_STRING, CRIRES_PARAM_TOT_NDIT) ;
197  crires_util_extract_config.y_pos_c1=crires_parameterlist_get_string(parlist,
198  RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP1) ;
199  crires_util_extract_config.y_pos_c2=crires_parameterlist_get_string(parlist,
200  RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP2) ;
201  crires_util_extract_config.y_pos_c3=crires_parameterlist_get_string(parlist,
202  RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP3) ;
203  crires_util_extract_config.y_pos_c4=crires_parameterlist_get_string(parlist,
204  RECIPE_STRING, CRIRES_PARAM_Y_POS_CHIP4) ;
205  crires_util_extract_config.y_width= crires_parameterlist_get_int(parlist,
206  RECIPE_STRING, CRIRES_PARAM_Y_WIDTH) ;
207  crires_util_extract_config.y_spec_zone_c1=crires_parameterlist_get_string(
208  parlist, RECIPE_STRING, CRIRES_PARAM_Y_SPEC_ZONE_CHIP1) ;
209  crires_util_extract_config.y_spec_zone_c2=crires_parameterlist_get_string(
210  parlist, RECIPE_STRING, CRIRES_PARAM_Y_SPEC_ZONE_CHIP2) ;
211  crires_util_extract_config.y_spec_zone_c3=crires_parameterlist_get_string(
212  parlist, RECIPE_STRING, CRIRES_PARAM_Y_SPEC_ZONE_CHIP3) ;
213  crires_util_extract_config.y_spec_zone_c4=crires_parameterlist_get_string(
214  parlist, RECIPE_STRING, CRIRES_PARAM_Y_SPEC_ZONE_CHIP4) ;
215 
216  sval = crires_parameterlist_get_string(parlist, RECIPE_STRING,
217  CRIRES_PARAM_REJECT) ;
218  if (sscanf(sval, "%d,%d",
219  &crires_util_extract_config.rej_left,
220  &crires_util_extract_config.rej_right)!=2) {
221  return -1 ;
222  }
223 
224  /* Identify the RAW and CALIB frames in the input frameset */
225  if (crires_dfs_set_groups(frameset, NULL)) {
226  cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
227  return -1 ;
228  }
229 
230  /* Get the detector illumination period */
231  fr = cpl_frameset_get_position(frameset, 0);
232  crires_util_extract_config.period =
233  crires_get_detector_illum_period(cpl_frame_get_filename(fr)) ;
234  if (crires_util_extract_config.period == CRIRES_ILLUM_UNKNOWN) {
235  cpl_msg_error(__func__,
236  "Cannot determine the detector illumination period") ;
237  return -1 ;
238  }
239 
240  /* Windowing mode ? */
241  if ((plist=cpl_propertylist_load(cpl_frame_get_filename(fr), 0)) == NULL)
242  return -1 ;
243  sval = crires_pfits_get_ncorrs(plist) ;
244  if (!strcmp(sval, "FowlerNsampGRstWin")) {
245  crires_util_extract_config.period = CRIRES_ILLUM_FULL_DETECTOR ;
246  crires_util_extract_config.win_mode = 1 ;
247  } else {
248  crires_util_extract_config.win_mode = 0 ;
249  }
250  cpl_propertylist_delete(plist) ;
251 
252  /* Display the Detector illumination */
253  crires_display_detector_illum(crires_util_extract_config.period) ;
254 
255  /* Load the first file in an image list */
256  cpl_msg_info(__func__, "Input image loading") ;
257  imlist = crires_load_file(cpl_frame_get_filename(fr),
258  crires_util_extract_config.period, CPL_TYPE_FLOAT) ;
259 
260  /* Load the optional contribution map */
261  if (cpl_frameset_get_size(frameset) >= 2) {
262  fr = cpl_frameset_get_position(frameset, 1);
263  cpl_msg_info(__func__, "Contribution map specified: %s",
264  cpl_frame_get_filename(fr)) ;
265  contrib = crires_load_file(cpl_frame_get_filename(fr),
266  crires_util_extract_config.period, CPL_TYPE_INT) ;
267  } else contrib = NULL ;
268 
269  if (crires_util_extract_config.mode == 1) {
270  /* Get the total ndit */
271  fr = cpl_frameset_get_position(frameset, 0);
272  if (crires_util_extract_config.tot_ndit < 0) {
273  crires_util_extract_config.tot_ndit =
274  crires_get_totndit(cpl_frame_get_filename(fr)) ;
275  if (crires_util_extract_config.tot_ndit < 0) {
276  cpl_msg_error(__func__,
277  "Cannot get the total number of NDIT*DIT") ;
278  cpl_imagelist_delete(imlist) ;
279  if (contrib != NULL) cpl_imagelist_delete(contrib) ;
280  return -1 ;
281  }
282  }
283  /* Get the number of exposures used for the frames combination */
284  plist=cpl_propertylist_load(cpl_frame_get_filename(fr), 0) ;
285  nexp = crires_pfits_get_datancom(plist) ;
286  cpl_propertylist_delete(plist) ;
287  if (cpl_error_get_code() != CPL_ERROR_NONE) {
288  cpl_msg_error(__func__,"No PRO DATANCOM information in the header");
289  cpl_imagelist_delete(imlist) ;
290  if (contrib != NULL) cpl_imagelist_delete(contrib) ;
291  return -1 ;
292  }
293  crires_util_extract_config.tot_ndit *= nexp ;
294  }
295 
296  /* Extract chips */
297  cpl_msg_info(__func__, "Spectrum extraction") ;
298  cpl_msg_indent_more() ;
299  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
300  /* Skip some detectors in windowing mode */
301  if ((i==0 || i==CRIRES_NB_DETECTORS-1) &&
302  (crires_util_extract_config.win_mode == 1)) {
303  continue ;
304  }
305  cpl_msg_info(__func__, "Spectrum extraction from chip number %d", i+1) ;
306  cpl_msg_indent_more() ;
307  if (crires_util_extract_config.mode == 1) {
308  /* Where is the spectrum extraction zone ? */
309  y_pos = "" ;
310  if (i+1 == 1) y_pos = crires_util_extract_config.y_spec_zone_c1 ;
311  if (i+1 == 2) y_pos = crires_util_extract_config.y_spec_zone_c2 ;
312  if (i+1 == 3) y_pos = crires_util_extract_config.y_spec_zone_c3 ;
313  if (i+1 == 4) y_pos = crires_util_extract_config.y_spec_zone_c4 ;
314  if (sscanf(y_pos,"%d,%d", &extr_spec_starty, &extr_spec_stopy)!=2) {
315  cpl_msg_warning(__func__, "Wrong Spectral Zone specified: %s",
316  y_pos) ;
317  extr_spec_starty = extr_spec_stopy = -1 ;
318  }
319 
320  /* Extract spectrum */
321  if (contrib != NULL)
322  contribution_map = cpl_imagelist_get(contrib, i) ;
323  else
324  contribution_map = NULL ;
325  ext[i] = crires_extract_spectrum(cpl_imagelist_get(imlist, i),
326  contribution_map,
327  crires_util_extract_config.box_hor_size,
328  crires_util_extract_config.spec_hsize,
329  crires_util_extract_config.kappa,
330  crires_util_extract_config.closing_hs,
331  crires_util_extract_config.clean_rate,
332  crires_util_extract_config.rej_left,
333  crires_util_extract_config.rej_right,
334  extr_spec_starty, extr_spec_stopy,
335  i+1,
336  crires_util_extract_config.tot_ndit,
337  crires_util_extract_config.period,
338  &(crires_util_extract_config.qc_specpos[i]),
339  &(crires_util_extract_config.qc_specwrec[i]),
340  &(crires_util_extract_config.qc_specwopt[i]),
341  &(crires_util_extract_config.qc_specoptmed[i]),
342  &(crires_util_extract_config.qc_s2nmed[i]),
343  &(prof[i]),
344  &(bgmap[i])) ;
345  cpl_msg_info(__func__, "Chip number %d FWHM Computation", i+1) ;
346  if (crires_extract_qc_fwhm(cpl_imagelist_get(imlist, i),
347  prof[i],
348  &(crires_util_extract_config.qc_fwhm_comb_pix[i]),
349  &(crires_util_extract_config.qc_fwhm_comb_as[i]),
350  &(crires_util_extract_config.qc_fwhm_prof_pix[i]),
351  &(crires_util_extract_config.qc_fwhm_prof_as[i]),
352  &(crires_util_extract_config.qc_fwhm_diff[i])) == -1) {
353  cpl_msg_warning(__func__, "Failed for FWHM computation") ;
354  crires_util_extract_config.qc_fwhm_comb_pix[i] = -1.0 ;
355  crires_util_extract_config.qc_fwhm_comb_as[i] = -1.0 ;
356  crires_util_extract_config.qc_fwhm_prof_pix[i] = -1.0 ;
357  crires_util_extract_config.qc_fwhm_prof_as[i] = -1.0 ;
358  crires_util_extract_config.qc_fwhm_diff[i] = -1.0 ;
359  }
360  } else if (crires_util_extract_config.mode == 2) {
361  /* Get the correction for the position */
362  if (i+1 == 1)
363  ly = crires_get_detector_ly1(crires_util_extract_config.period);
364  if (i+1 == 2)
365  ly = crires_get_detector_ly2(crires_util_extract_config.period);
366  if (i+1 == 3)
367  ly = crires_get_detector_ly3(crires_util_extract_config.period);
368  if (i+1 == 4)
369  ly = crires_get_detector_ly4(crires_util_extract_config.period);
370  /* If ly not found, use the bottom of the image */
371  if (ly < 0) ly = 1 ;
372 
373  /* Where is the Y extraction zone ? */
374  y_pos = "" ;
375  if (i+1 == 1) y_pos = crires_util_extract_config.y_pos_c1 ;
376  if (i+1 == 2) y_pos = crires_util_extract_config.y_pos_c2 ;
377  if (i+1 == 3) y_pos = crires_util_extract_config.y_pos_c3 ;
378  if (i+1 == 4) y_pos = crires_util_extract_config.y_pos_c4 ;
379 
380  /* Try to parse the user specified positions */
381  if (!strcmp(y_pos, "")) {
382  ypos_vec = NULL ;
383  } else {
384  if ((ypos_vec = crires_parse_y_positions(y_pos)) == NULL) {
385  cpl_msg_warning(__func__,
386  "Cannot parse the y_positions value : %s", y_pos) ;
387  ypos_vec = NULL ;
388  }
389  }
390 
391  if (ypos_vec == NULL) {
392  cpl_msg_info(__func__, "Collapse the full image along Y") ;
393  starty = 1 ;
394  stopy = cpl_image_get_size_y(cpl_imagelist_get(imlist, i)) ;
395  } else {
396  cpl_msg_info(__func__, "Collapse the area around Y=%g",
397  cpl_vector_get(ypos_vec, 0)) ;
398  /* TODO : Only the first passed value is used */
399  starty = (int)cpl_vector_get(ypos_vec, 0) -
400  (int)(crires_util_extract_config.y_width/2.0) ;
401  stopy = (int)cpl_vector_get(ypos_vec, 0) +
402  (int)(crires_util_extract_config.y_width/2.0) ;
403  cpl_vector_delete(ypos_vec) ;
404  starty -= ly-1 ;
405  stopy -= ly-1 ;
406  }
407 
408  /* Extract lines */
409  ext_vec = crires_extract_lines(cpl_imagelist_get(imlist, i),
410  starty, stopy,
411  crires_util_extract_config.rej_left,
412  crires_util_extract_config.rej_right) ;
413  if (ext_vec != NULL) {
414  ext[i] = crires_extract_gen_tab(ext_vec, NULL, NULL, NULL,
415  NULL, NULL, NULL) ;
416  crires_util_extract_config.qc_specpos[i] =
417  (starty+stopy)/2 + (ly-1) ;
418  crires_util_extract_config.qc_specwrec[i] = starty-stopy+1;
419  cpl_vector_delete(ext_vec) ;
420  }
421  } else {
422  cpl_msg_warning(__func__, "Unsuported mode: %d",
423  crires_util_extract_config.mode) ;
424  }
425 
426  /* Plot the result if required */
427  if ((ext[i] != NULL) && (crires_util_extract_config.display == i+1)) {
428  ext_vec = cpl_vector_wrap(cpl_table_get_nrow(ext[i]),
429  cpl_table_get_data_double(ext[i], CRIRES_COL_EXTRACT_INT_RECT));
430  cpl_plot_vector(
431 "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity RECT (ADU/sec)';",
432  "t 'Extracted Spectrum RECT' w lines", "", ext_vec) ;
433  cpl_vector_unwrap(ext_vec) ;
434  ext_vec = cpl_vector_wrap(cpl_table_get_nrow(ext[i]),
435  cpl_table_get_data_double(ext[i], CRIRES_COL_EXTRACT_INT_OPT)) ;
436  cpl_plot_vector(
437 "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity OPT (ADU/sec)';",
438  "t 'Extracted Spectrum OPT' w lines", "", ext_vec) ;
439  cpl_vector_unwrap(ext_vec) ;
440  }
441  cpl_msg_indent_less() ;
442  }
443  cpl_imagelist_delete(imlist) ;
444  if (contrib != NULL) cpl_imagelist_delete(contrib) ;
445  cpl_msg_indent_less() ;
446 
447  /* Reconstruct chips in windowing mode using detector 2 */
448  if (crires_util_extract_config.win_mode == 1) {
449  if (ext[1] != NULL) {
450  ext[0] = cpl_table_duplicate(ext[1]) ;
451  cpl_table_set_size(ext[0], 0) ;
452  ext[CRIRES_NB_DETECTORS-1] = cpl_table_duplicate(ext[0]) ;
453  }
454  if (prof[1] != NULL) {
455  prof[0] = cpl_image_duplicate(prof[1]) ;
456  cpl_image_multiply_scalar(prof[0], 0.0) ;
457  prof[CRIRES_NB_DETECTORS-1] = cpl_image_duplicate(prof[0]) ;
458  }
459  if (bgmap[1] != NULL) {
460  bgmap[0] = cpl_image_duplicate(bgmap[1]) ;
461  cpl_image_multiply_scalar(bgmap[0], 0.0) ;
462  bgmap[CRIRES_NB_DETECTORS-1] = cpl_image_duplicate(bgmap[0]) ;
463  }
464  }
465 
466  /* Test that the spectrum is at the same place in all detectors */
467  for (i=1 ; i<CRIRES_NB_DETECTORS ; i++) {
468  /* Skip some detectors in windowing mode */
469  if ((i==1 || i==CRIRES_NB_DETECTORS-1) &&
470  (crires_util_extract_config.win_mode == 1)) {
471  continue ;
472  }
473  if (crires_util_extract_config.qc_specpos[i-1] > 0 &&
474  crires_util_extract_config.qc_specpos[i] > 0 &&
475  fabs(crires_util_extract_config.qc_specpos[i-1] -
476  crires_util_extract_config.qc_specpos[i]) >
477  CRIRES_SPEC_POS_TOLERANCE) {
478  cpl_msg_warning(__func__,
479  "The spectrum positions in chip %d and chip %d are too different: %d -> %d",
480  i, i+1, crires_util_extract_config.qc_specpos[i-1],
481  crires_util_extract_config.qc_specpos[i]) ;
482  }
483  }
484 
485  /* Create the profile */
486  profile = cpl_imagelist_new() ;
487  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
488  if (prof[i] != NULL) cpl_imagelist_set(profile, prof[i], i) ;
489  else {
490  cpl_imagelist_delete(profile) ;
491  profile = NULL ;
492  for (j=i+1 ; j<CRIRES_NB_DETECTORS ; j++)
493  if (prof[j] != NULL) cpl_image_delete(prof[j]) ;
494  break ;
495  }
496  }
497 
498  /* Create the bg maps */
499  bgmaps = cpl_imagelist_new() ;
500  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
501  if (bgmap[i] != NULL) cpl_imagelist_set(bgmaps, bgmap[i], i) ;
502  else {
503  cpl_imagelist_delete(bgmaps) ;
504  bgmaps = NULL ;
505  for (j=i+1 ; j<CRIRES_NB_DETECTORS ; j++)
506  if (bgmap[j] != NULL) cpl_image_delete(bgmap[j]) ;
507  break ;
508  }
509  }
510 
511  /* Save the result */
512  cpl_msg_info(__func__, "Save the products") ;
513  cpl_msg_indent_more() ;
514  if (crires_util_extract_save((const cpl_table **)ext, profile, bgmaps,
515  parlist, frameset) == -1) {
516  cpl_msg_error(__func__, "Cannot save products") ;
517  cpl_msg_indent_less() ;
518  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
519  if (ext[i] != NULL) cpl_table_delete(ext[i]) ;
520  }
521  if (profile != NULL) cpl_imagelist_delete(profile) ;
522  if (bgmaps != NULL) cpl_imagelist_delete(bgmaps) ;
523  return -1 ;
524  }
525  cpl_msg_indent_less() ;
526 
527  /* Deallocate */
528  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
529  if (ext[i] != NULL) cpl_table_delete(ext[i]) ;
530  }
531  if (profile != NULL) cpl_imagelist_delete(profile) ;
532  if (bgmaps != NULL) cpl_imagelist_delete(bgmaps) ;
533 
534  /* Return */
535  if (cpl_error_get_code()) return -1 ;
536  else return 0 ;
537 }
538 
539 /*----------------------------------------------------------------------------*/
549 /*----------------------------------------------------------------------------*/
550 static int crires_util_extract_save(
551  const cpl_table ** ext,
552  const cpl_imagelist * profile,
553  const cpl_imagelist * bgmaps,
554  const cpl_parameterlist * parlist,
555  cpl_frameset * set)
556 {
557  cpl_propertylist ** qclists ;
558  const cpl_frame * ref_frame ;
559  cpl_propertylist * inputlist ;
560  const char * recipe_name = "crires_util_extract" ;
561  int i ;
562 
563  /* Get the reference frame */
564  ref_frame = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW) ;
565 
566  /* Create the QC lists */
567  qclists = cpl_malloc(CRIRES_NB_DETECTORS * sizeof(cpl_propertylist*)) ;
568  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
569  qclists[i] = cpl_propertylist_new() ;
570  cpl_propertylist_append_int(qclists[i], "ESO QC SPECPOS",
571  crires_util_extract_config.qc_specpos[i]) ;
572  cpl_propertylist_append_int(qclists[i], "ESO QC SPECWREC",
573  crires_util_extract_config.qc_specwrec[i]) ;
574  cpl_propertylist_append_int(qclists[i], "ESO QC SPECWOPT",
575  crires_util_extract_config.qc_specwopt[i]) ;
576  cpl_propertylist_append_double(qclists[i], "ESO QC SIGNAL MED",
577  crires_util_extract_config.qc_specoptmed[i]) ;
578  cpl_propertylist_append_double(qclists[i], "ESO QC S2NMED",
579  crires_util_extract_config.qc_s2nmed[i]) ;
580  cpl_propertylist_append_double(qclists[i], "ESO QC FWHMPIX COMBINED",
581  crires_util_extract_config.qc_fwhm_comb_pix[i]) ;
582  cpl_propertylist_append_double(qclists[i], "ESO QC FWHMARC COMBINED",
583  crires_util_extract_config.qc_fwhm_comb_as[i]) ;
584  cpl_propertylist_append_double(qclists[i], "ESO QC FWHMPIX PROFILE",
585  crires_util_extract_config.qc_fwhm_prof_pix[i]) ;
586  cpl_propertylist_append_double(qclists[i], "ESO QC FWHMARC PROFILE",
587  crires_util_extract_config.qc_fwhm_prof_as[i]) ;
588  cpl_propertylist_append_double(qclists[i], "ESO QC FWHM DIFF",
589  crires_util_extract_config.qc_fwhm_diff[i]) ;
590 
591  /* Propagate some keywords from input raw frame extensions */
592  inputlist = cpl_propertylist_load_regexp(
593  cpl_frame_get_filename(ref_frame), i+1,
594  CRIRES_HEADER_EXT_FORWARD, 0) ;
595  cpl_propertylist_copy_property_regexp(qclists[i], inputlist,
596  CRIRES_HEADER_EXT_FORWARD, 0) ;
597  cpl_propertylist_delete(inputlist) ;
598  }
599 
600  if (profile != NULL) {
601  /* Write the image */
602  crires_image_save(set,
603  parlist,
604  set,
605  profile,
606  recipe_name,
607  CRIRES_OBS_EXTRACT_PROFILE_IMA,
608  CRIRES_PROTYPE_PROFILE,
609  crires_util_extract_config.period,
610  NULL,
611  (const cpl_propertylist**)qclists,
612  PACKAGE "/" PACKAGE_VERSION,
613  "crires_util_extract_profile.fits") ;
614  }
615 
616  if (bgmaps!= NULL) {
617  /* Write the image */
618  crires_image_save(set,
619  parlist,
620  set,
621  bgmaps,
622  recipe_name,
623  CRIRES_OBS_EXTRACT_BGMAP_IMA,
624  CRIRES_PROTYPE_BGD_MAP,
625  crires_util_extract_config.period,
626  NULL,
627  (const cpl_propertylist**)qclists,
628  PACKAGE "/" PACKAGE_VERSION,
629  "crires_util_extract_bgmap.fits") ;
630  }
631 
632  /* Write the table */
633  crires_table_save(set,
634  parlist,
635  set,
636  ext,
637  recipe_name,
638  CRIRES_EXTRACT_PIX_TAB,
639  CRIRES_PROTYPE_SPEC_PIX,
640  NULL,
641  (const cpl_propertylist**)qclists,
642  PACKAGE "/" PACKAGE_VERSION,
643  "crires_util_extract_extracted.fits") ;
644 
645  /* Free and return */
646  for (i=0 ; i<CRIRES_NB_DETECTORS ; i++) {
647  cpl_propertylist_delete(qclists[i]) ;
648  }
649  cpl_free(qclists) ;
650  return 0;
651 }
652